pmacro_ruly 0.2.0

macros for ruly
Documentation
extern crate proc_macro;
use proc_macro::{Delimiter, TokenStream, TokenTree};

#[proc_macro]
#[doc(hidden)]
pub fn create_enum(item: TokenStream) -> TokenStream {
    let input: Vec<TokenTree> = item.into_iter().collect();

    let mut s;

    if let (Some(TokenTree::Group(g1)), Some(TokenTree::Group(g2))) = (input.get(0), input.get(1)) {
        if let Some(TokenTree::Ident(id1)) = g1.stream().into_iter().next() {
            s = format!(
                "#[derive(Debug, Eq, PartialEq, Clone)]\npub enum {}{}\n",
                id1.to_string(),
                r"{"
            );

            for tmp in g2.stream() {
                // tmp corresponds to a variant
                if let TokenTree::Group(g21) = tmp {
                    let gv: Vec<TokenTree> = g21.stream().into_iter().collect();

                    if let (Some(TokenTree::Group(g211)), Some(TokenTree::Group(g212))) =
                        (gv.get(0), gv.get(1))
                    {
                        // g211 corresponds to variant name, and g212 to a tuple of types
                        if let Some(TokenTree::Ident(id2)) = g211.stream().into_iter().next() {
                            s += &format!("    {}(", id2.to_string());

                            for tree in g212.stream() {
                                match tree {
                                    TokenTree::Ident(id) => {
                                        // Box<T>
                                        s += &format!("Box<{}>", id.to_string());
                                    }

                                    TokenTree::Group(g) => {
                                        if g.delimiter() == Delimiter::Brace {
                                            // regex
                                            let gvv: Vec<TokenTree> =
                                                g.stream().into_iter().collect();

                                            if let Some(hoge) = gvv.get(0) {
                                                match hoge {
                                                    TokenTree::Group(_) => {
                                                        // regex
                                                        if let None = gvv.get(1) {
                                                            // String
                                                            s += "String";
                                                        } else if let Some(TokenTree::Ident(idd)) =
                                                            gvv.get(2)
                                                        {
                                                            // (String, T)
                                                            s += &format!(
                                                                "(String,{})",
                                                                idd.to_string()
                                                            );
                                                        } else {
                                                            panic!("syntax error7.");
                                                        }
                                                    }

                                                    TokenTree::Ident(_) => {
                                                        // reserved word
                                                        if let None = gvv.get(2) {
                                                            // String
                                                            s += "String";
                                                        } else if let Some(TokenTree::Ident(idd)) =
                                                            gvv.get(3)
                                                        {
                                                            // (String, T)
                                                            s += &format!(
                                                                "(String,{})",
                                                                idd.to_string()
                                                            );
                                                        } else {
                                                            panic!("syntax error7.");
                                                        }
                                                    }

                                                    _ => {
                                                        panic!("syntax error10.");
                                                    }
                                                }
                                            } else {
                                                panic!("syntax error9.");
                                            }
                                        } else if g.delimiter() == Delimiter::Parenthesis {
                                            // Vec<T>
                                            if let Some(TokenTree::Ident(id)) =
                                                g.stream().into_iter().next()
                                            {
                                                s += &format!("Vec<{}>", id.to_string());
                                            } else {
                                                panic!("syntax error8.");
                                            }
                                        } else {
                                            panic!("syntax error9.");
                                        }
                                    }

                                    TokenTree::Punct(_) => {
                                        s += ",";
                                    }

                                    _ => {
                                        panic!("syntax error6.");
                                    }
                                }
                            }

                            s += "),\n";
                        } else {
                            panic!("syntax error5.");
                        }
                    } else {
                        panic!("syntax error4.");
                    }
                }
            }

            s += r"}";
        } else {
            panic!("syntax error2.");
        }
    } else {
        panic!("syntax error1.");
    }

    s.parse().unwrap()
}

#[proc_macro]
#[doc(hidden)]
pub fn create_match(item: TokenStream) -> TokenStream {
    let input: Vec<TokenTree> = item.into_iter().collect();
    let mut n: u32 = 0;

    let mut s;

    if let (Some(TokenTree::Group(g1)), Some(TokenTree::Group(g2))) = (input.get(0), input.get(1)) {
        if let Some(TokenTree::Ident(id1)) = g1.stream().into_iter().next() {
            s = format!("match self{}", r"{");

            for tmp in g2.stream() {
                if let TokenTree::Group(g21) = tmp {
                    let gv: Vec<TokenTree> = g21.stream().into_iter().collect();

                    if let (Some(TokenTree::Group(g211)), Some(TokenTree::Group(g212))) =
                        (gv.get(0), gv.get(1))
                    {
                        if let Some(TokenTree::Ident(id2)) = g211.stream().into_iter().next() {
                            let mut val = format!("{}::{}(", id1, id2);
                            let mut exp = r"{".to_string();

                            for tree in g212.stream() {
                                match tree {
                                    TokenTree::Ident(_) => {
                                        // Box<T>
                                        val += "field";
                                        val += &format!("{}", n);

                                        exp +=
                                            &format!(r#"write!(f,"{}{}",field{});"#, r"{", r"}", n);

                                        n += 1;
                                    }

                                    TokenTree::Group(g) => {
                                        if g.delimiter() == Delimiter::Brace {
                                            // regex
                                            val += "field";
                                            val += &format!("{}", n);

                                            let gvv: Vec<TokenTree> =
                                                g.stream().into_iter().collect();

                                            if let Some(hoge) = gvv.get(0) {
                                                match hoge {
                                                    TokenTree::Group(_) => {
                                                        // regex
                                                        if let None = gvv.get(1) {
                                                            // String
                                                            exp += &format!(
                                                                r#"write!(f,"{}{}",field{});"#,
                                                                r"{", r"}", n
                                                            );
                                                        } else if let Some(TokenTree::Ident(_)) =
                                                            gvv.get(2)
                                                        {
                                                            // (String, T)
                                                            exp += &format!(
                                                                r#"write!(f,"{}{}",field{}.0);"#,
                                                                r"{", r"}", n
                                                            );
                                                        } else {
                                                            panic!("syntax error7.");
                                                        }
                                                    }

                                                    TokenTree::Ident(_) => {
                                                        // reserved word
                                                        if let None = gvv.get(2) {
                                                            // String
                                                            exp += &format!(
                                                                r#"write!(f,"{}{}",field{});"#,
                                                                r"{", r"}", n
                                                            );
                                                        } else if let Some(TokenTree::Ident(_)) =
                                                            gvv.get(3)
                                                        {
                                                            // (String, T)
                                                            exp += &format!(
                                                                r#"write!(f,"{}{}",field{}.0);"#,
                                                                r"{", r"}", n
                                                            );
                                                        } else {
                                                            panic!("syntax error7.");
                                                        }
                                                    }

                                                    _ => {
                                                        panic!("syntax error10.");
                                                    }
                                                }
                                            } else {
                                                panic!("syntax error9.");
                                            }
                                        } else if g.delimiter() == Delimiter::Parenthesis {
                                            // Vec<T>
                                            val += "field";
                                            val += &format!("{}", n);

                                            if let Some(TokenTree::Ident(_)) =
                                                g.stream().into_iter().next()
                                            {
                                                exp += &format!(
                                                    r#"for (i, tmp) in field{}.into_iter().enumerate() {}if i>0 {}write!(f," ");{}write!(f,"{}{}",tmp);{}"#,
                                                    n, r"{", r"{", r"}", r"{", r"}", r"}"
                                                );
                                            } else {
                                                panic!("syntax error8.");
                                            }
                                        } else {
                                            panic!("syntax error9.");
                                        }

                                        n += 1;
                                    }

                                    TokenTree::Punct(_) => {
                                        val += ",";
                                        exp += &format!(r#"write!(f," ");"#);
                                    }

                                    _ => {
                                        panic!("syntax error6.");
                                    }
                                }
                            }

                            val += ")";
                            exp += r"}";

                            s += &val;
                            s += "=>";
                            s += &exp;
                        } else {
                            panic!("syntax error5.");
                        }
                    } else {
                        panic!("syntax error4.");
                    }
                }
            }

            s += r"}";
        } else {
            panic!("syntax error2.");
        }
    } else {
        panic!("syntax error1.");
    }

    s.parse().unwrap()
}