use proc_macro::{TokenTree, TokenStream};
pub fn error(error: &str) -> TokenStream {
let safe_str = error.replace('"', "\\\"");
format!("compile_error!(\"{}\")",safe_str).parse().unwrap()
}
fn unbox_group(tree: TokenTree) -> TokenTree {
match &tree {
TokenTree::Group(g) => {
let mut iter = g.stream().into_iter();
let unboxed = match iter.next() {
Some(u) => u,
None => TokenTree::Group(g.to_owned())
};
match iter.next() {
Some(_) => TokenTree::Group(g.to_owned()),
None => unboxed
}
}
other => other.to_owned()
}
}
#[derive(Debug)]
pub enum ParsedLiteral {
RawLiteral(()),
Literal(String)
}
impl ParsedLiteral {
pub fn unwrap_literal(self) -> String {
match self {
ParsedLiteral::Literal(l) => l,
ParsedLiteral::RawLiteral(_) => panic!("Can't use a raw literal")
}
}
}
pub fn parse_literal_string<I: Iterator<Item=TokenTree>>(iterator: &mut I) -> Result<ParsedLiteral,String> {
let next = match iterator.next() {
Some(u) => u,
None => { return Err("Nothing found.".to_string())}
};
let unboxed_next = unbox_group(next);
match unboxed_next {
TokenTree::Literal(s) if s.to_string().starts_with('"') => {
let mut parsed_string = s.to_string();
parsed_string.remove(parsed_string.len()-1);
parsed_string.remove(0);
Ok(
ParsedLiteral::Literal(parsed_string)
)
},
TokenTree::Literal(s) if s.to_string().starts_with("r#\"") => {
let mut parsed_string = s.to_string();
parsed_string.remove(parsed_string.len()-1);
parsed_string.remove(parsed_string.len()-1);
parsed_string.remove(0);
parsed_string.remove(0);
parsed_string.remove(0);
Ok(ParsedLiteral::RawLiteral(()))
}
other => {
Err(format!("unexpected {:?}",other))
}
}
}
pub fn parse_ident<I: Iterator<Item=TokenTree>>(iterator: &mut I) -> Result<String,String> {
let next = match iterator.next() {
Some(u) => u,
None => { return Err("Nothing found.".to_string()) }
};
let unboxed_next = unbox_group(next);
match unboxed_next {
TokenTree::Ident(s) => { Ok(s.to_string()) }
other => {
Err(format!("unexpected {:?}", other))
}
}
}
pub fn parse_type<I: Iterator<Item=TokenTree>>(iterator: &mut I) -> Result<String,String> {
let next = match iterator.next() {
Some(u) => u,
None => { return Err("Nothing found.".to_string()) }
};
let unboxed_next = unbox_group(next);
match unboxed_next {
TokenTree::Ident(s) => { Ok(s.to_string()) }
TokenTree::Group(g) => {
let mut iter = g.stream().into_iter();
let mut parsed = String::new();
loop {
let next = match iter.next() {
Some(u) => u,
None => { break; }
};
match next {
TokenTree::Ident(s) => {
parsed.push_str(&s.to_string());
}
TokenTree::Punct(p) => {
parsed.push_str(&p.to_string());
}
TokenTree::Literal(l) => {
parsed.push_str(&l.to_string());
}
TokenTree::Group(g) => {
parsed.push_str(&g.to_string());
}
}
}
if parsed == "" || parsed == "()".to_string() {
Ok("()".to_string())
}
else {
Err(format!("while parsing a type, group, {:?}", parsed))
}
}
other => {
Err(format!("unexpected {:?}", other))
}
}
}
pub fn parse_ident_or_literal<I: Iterator<Item=TokenTree> + Clone>(iterator: &mut I) -> Result<String,String> {
let iterator_backup = iterator.clone();
match parse_literal_string(iterator) {
Ok(ParsedLiteral::Literal(l)) => {Ok(l)}
_ => {
*iterator = iterator_backup;
match parse_ident(iterator) {
Ok(ident) => {Ok(ident)}
Err(e) => {Err(e)}
}
}
}
}