squark_macros/
lib.rs

1#![crate_type = "proc-macro"]
2#![feature(proc_macro_hygiene, proc_macro_quote)]
3
4extern crate pest;
5#[macro_use]
6extern crate pest_derive;
7extern crate proc_macro;
8
9use parser::{Parser as ViewParser, Rule};
10use pest::iterators::{Pair, Pairs};
11use pest::Parser;
12use proc_macro::{quote, Literal, TokenStream, TokenTree};
13use std::iter::FromIterator;
14use std::str::FromStr;
15
16mod parser {
17    #[derive(Parser)]
18    #[grammar = "view.pest"]
19    pub struct Parser;
20}
21
22fn get_token_stream(mut tag_pairs: Pairs<Rule>) -> TokenStream {
23    let name = tag_pairs.next().expect("name").as_str();
24    let _name = TokenTree::Literal(Literal::string(name));
25
26    let mut attributes = vec![];
27    let mut handlers = vec![];
28
29    let vec: Vec<Pair<Rule>> = tag_pairs.next().expect("attributes").into_inner().collect();
30    for i in 0..(vec.len() / 2) {
31        let j = i * 2;
32        let k = &vec[j].as_str();
33        let v = &vec[j + 1];
34
35        let _v = match v.as_rule() {
36            Rule::embedded => {
37                let mut _embedded = TokenStream::from_str(v.as_str()).unwrap();
38                quote!($_embedded.into())
39            }
40            Rule::string => {
41                let _v = TokenTree::Literal(Literal::string(v.as_str()));
42                quote! { $_v.into() }
43            }
44            Rule::bool => {
45                let _v = TokenStream::from_str(v.as_str()).unwrap();
46                quote! { $_v.into() }
47            }
48            _ => unreachable!(),
49        };
50
51        if k.starts_with("on") {
52            let (_, k) = k.split_at(2);
53            let _k = TokenTree::Literal(Literal::string(k));
54            handlers.push(quote! {
55                ($_k.to_string(), _squark::handler($_v)),
56            });
57            continue;
58        }
59
60        let _k = TokenTree::Literal(Literal::string(k));
61        attributes.push(quote! {
62            ($_k.to_string(), $_v),
63        });
64    }
65    let _attributes = TokenStream::from_iter(attributes);
66    let _handlers = TokenStream::from_iter(handlers);
67
68    let mut children = vec![];
69    if let Some(children_pair) = tag_pairs.next() {
70        for p in children_pair.into_inner() {
71            let token = match p.as_rule() {
72                Rule::tag => {
73                    let _tag = get_token_stream(p.into_inner());
74                    quote! {
75                        _squark::Child::from($_tag),
76                    }
77                }
78                Rule::text => {
79                    let _text = TokenTree::Literal(Literal::string(p.as_str()));
80                    quote! {
81                        $_text.into(),
82                    }
83                }
84                Rule::embedded => {
85                    let _embedded = TokenStream::from_str(p.as_str()).unwrap();
86                    quote! {
87                        {$_embedded}.into(),
88                    }
89                }
90                _ => unreachable!(),
91            };
92            children.push(token);
93        }
94    }
95    let _children = TokenStream::from_iter(children);
96
97    quote! {
98        _squark::View::new(
99            $_name.to_string(),
100            vec![
101                $_attributes
102            ],
103            vec![
104                $_handlers
105            ],
106            vec![
107                $_children
108            ]
109        )
110    }
111}
112
113#[proc_macro]
114pub fn view(arg: TokenStream) -> TokenStream {
115    let s = arg.to_string();
116    let mut pairs = ViewParser::parse(Rule::view, &s).unwrap();
117    let _token = get_token_stream(pairs.next().unwrap().into_inner());
118
119    quote! {
120        {
121            extern crate squark as _squark;
122            $_token
123        }
124    }
125}