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}