#![feature(proc_macro_diagnostic)]
#![feature(extend_one)]
extern crate proc_macro;
use proc_macro::*;
use litrs;
fn parse_punct(t: TokenStream) -> Option<Vec<String>> {
let mut output = vec![];
let mut expect_punct = false;
for curr_tok in t.into_iter() {
match curr_tok {
TokenTree::Literal(ref val) => {
let parsed_literal = litrs::Literal::from(val);
match parsed_literal {
litrs::Literal::String(parsed_val) => {
if expect_punct {
return None;
}
output.push(parsed_val.value().to_string());
},
_ => {
val.span().error("Unexpected punctuation or punctuation type").emit();
return None;
}
};
},
TokenTree::Punct(val) => {
if !expect_punct || val.as_char() != ',' {
val.span().error("Unexpected punctuation or punctuation type").emit();
return None;
}
},
unexpected_token => {
unexpected_token.span().error("Unexpected token").emit();
return None;
}
}
expect_punct = !expect_punct;
}
Some(output)
}
macro_rules! include_path_macro {
($original_ident: literal, $new_ident: ident, $for_windows: expr) => {
#[proc_macro]
pub fn $new_ident(t: TokenStream) -> TokenStream {
let mut output = TokenStream::from(
TokenTree::from(
Ident::new($original_ident, Span::call_site())
)
);
output.extend_one(
TokenTree::from(
Punct::new('!',Spacing::Alone)
)
);
let literals = match parse_punct(t) {
Some(val) => val,
None => { return TokenStream::new() }
};
let joined_path;
if $for_windows {
joined_path = Literal::string(& literals.join("\\"));
} else {
joined_path = Literal::string(&literals.join("/"));
}
output.extend_one(
TokenTree::from(
Group::new(
Delimiter::Parenthesis,
TokenStream::from(
TokenTree::from(joined_path)
)
)
)
);
output
}
}
}
#[cfg( host_family ="windows")]
static FOR_WINDOWS: bool = true;
#[cfg(not(host_family = "windows"))]
static FOR_WINDOWS: bool = false;
include_path_macro!("include",include_path,FOR_WINDOWS);
include_path_macro!("include_bytes",include_path_bytes,FOR_WINDOWS);
include_path_macro!("include_str",include_path_str,FOR_WINDOWS);