view_macro/
lib.rs

1extern crate proc_macro;
2use proc_macro_hack::proc_macro_hack;
3use proc_macro::{Delimiter, TokenStream, TokenTree};
4//use std::collections::HashMap;
5use std::iter::Peekable;
6use std::str::FromStr;
7
8type PeekableTokenStream = Peekable<proc_macro::token_stream::IntoIter>;
9
10#[derive(Debug)]
11enum NodeType {
12    Empty,
13    If(String),
14    For(String),
15    Simple(String),
16    Params(String),
17}
18
19#[derive(Debug)]
20struct NodeModifier {
21    function: String,
22    parameters: String,
23}
24
25#[derive(Debug)]
26struct Node {
27    name: String,
28    node_type: NodeType,
29    modifiers: Option<Vec<NodeModifier>>,
30    children: Option<Vec<Node>>,
31}
32
33impl Node {
34    fn parse_view_node_children(
35        mut input: PeekableTokenStream,
36    ) -> Result<(Option<Vec<Node>>, PeekableTokenStream), String> {
37        let mut has_children = false;
38        if let Some(TokenTree::Group(t)) = input.peek() {
39            if t.delimiter() == Delimiter::Brace {
40                has_children = true;
41            } else {
42                return Err("unexpected punctuation syntax of child start".to_owned());
43            }
44        }
45
46        let mut node_children = None;
47        if has_children {
48            let mut child_input: Option<PeekableTokenStream> = None;
49            if let Some(TokenTree::Group(t)) = input.next() {
50                child_input = Some(t.stream().into_iter().peekable());
51            }
52
53            if let Some(mut child_input) = child_input {
54                let mut children = vec![];
55                loop {
56                    if let None = child_input.peek() {
57                        break;
58                    } else {
59                        let (n, i) = Node::parse_view_node(child_input)?;
60                        child_input = i;
61                        children.push(n)
62                    }
63                }
64                node_children = Some(children)
65            } else {
66                return Err("I have no idea how you'd get here".to_owned());
67            }
68        }
69        Ok((node_children, input))
70    }
71
72    fn parse_view_node_args(
73        mut input: PeekableTokenStream,
74    ) -> Result<(Option<String>, bool, PeekableTokenStream), String> {
75        let mut is_structured = true;
76        let mut has_args = false;
77        if let Some(TokenTree::Group(t)) = input.peek() {
78            if t.delimiter() == Delimiter::Parenthesis {
79                has_args = true;
80            }
81        }
82
83        let mut args = None;
84        if has_args {
85            if let Some(TokenTree::Group(t)) = input.next() {
86                {
87                    let mut s = t.stream().into_iter();
88                    {
89                        if let Some(TokenTree::Ident(_)) = s.next() {
90                        } else {
91                            is_structured = false;
92                        }
93                    }
94                    if is_structured {
95                        if let Some(TokenTree::Punct(p)) = s.next() {
96                            if p.as_char() != ':' {
97                                is_structured = false;
98                            }
99                        } else {
100                            is_structured = false;
101                        }
102                    }
103                }
104                args = Some(t.stream().to_string());
105            }
106        } else {
107            is_structured = false;
108        }
109        Ok((args, is_structured, input))
110    }
111
112    fn parse_view_node_mods(
113        mut input: PeekableTokenStream,
114    ) -> Result<(Option<Vec<NodeModifier>>, PeekableTokenStream), String> {
115        let mut mods = vec![];
116        loop {
117            if let Some(TokenTree::Punct(p)) = input.peek() {
118                if p.as_char() != '.' {
119                    break;
120                }
121            } else {
122                break;
123            }
124            input.next();
125            let mut name = None;
126            if let Some(TokenTree::Ident(i)) = input.next() {
127                name = Some(i.to_string());
128            }
129            if let Some(function_name) = name {
130                if let Some(TokenTree::Group(g)) = input.next() {
131                    if g.delimiter() == Delimiter::Parenthesis {
132                        mods.push(NodeModifier {
133                            function: function_name,
134                            parameters: g.stream().to_string(),
135                        })
136                    }
137                }
138            } else {
139                return Err("unexpected function name after .".to_owned());
140            }
141        }
142        if mods.len() == 0 {
143            Ok((None, input))
144        } else {
145            Ok((Some(mods), input))
146        }
147    }
148
149    fn parse_if_view(
150        mut input: PeekableTokenStream,
151    ) -> Result<(Node, PeekableTokenStream), String> {
152        let (args, _, i) = Node::parse_view_node_args(input)?;
153        input = i;
154        if args.is_none() {
155            return Err("if requires arguments".to_string());
156        }
157        let (children, i) = Node::parse_view_node_children(input)?;
158        input = i;
159        if children.is_none() {
160            return Err("if requires children".to_string());
161        }
162        let e = Node {
163            name: "If".to_string(),
164            node_type: NodeType::If(args.unwrap()),
165            modifiers: None,
166            children: children,
167        };
168        Ok((e, input))
169    }
170
171    fn parse_for_view(
172        mut input: PeekableTokenStream,
173    ) -> Result<(Node, PeekableTokenStream), String> {
174        let (args, _, i) = Node::parse_view_node_args(input)?;
175        input = i;
176        if args.is_none() {
177            return Err("for requires arguments".to_string());
178        }
179        let (children, i) = Node::parse_view_node_children(input)?;
180        input = i;
181        if children.is_none() {
182            return Err("for requires children".to_string());
183        }
184        let e = Node {
185            name: "For".to_string(),
186            node_type: NodeType::For(args.unwrap()),
187            modifiers: None,
188            children: children,
189        };
190        Ok((e, input))
191    }
192
193    fn parse_user_view(
194        name: String,
195        mut input: PeekableTokenStream,
196    ) -> Result<(Node, PeekableTokenStream), String> {
197        let (args, structed_args, i) = Node::parse_view_node_args(input)?;
198        input = i;
199        let (mods, i) = Node::parse_view_node_mods(input)?;
200        input = i;
201        let (children, i) = Node::parse_view_node_children(input)?;
202        input = i;
203        if args.is_none() {
204            let e = Node {
205                name: name,
206                node_type: NodeType::Empty,
207                modifiers: mods,
208                children: children,
209            };
210            Ok((e, input))
211        } else {
212            if structed_args {
213                let e = Node {
214                    name: name,
215                    node_type: NodeType::Params(args.unwrap()),
216                    modifiers: mods,
217                    children: children,
218                };
219                Ok((e, input))
220            } else {
221                let e = Node {
222                    name: name,
223                    node_type: NodeType::Simple(args.unwrap()),
224                    modifiers: mods,
225                    children: children,
226                };
227                Ok((e, input))
228            }
229        }
230    }
231
232    fn parse_view_node(
233        mut input: PeekableTokenStream,
234    ) -> Result<(Node, PeekableTokenStream), String> {
235        let mut node_name = None;
236        if let Some(TokenTree::Ident(name)) = input.next() {
237            node_name = Some(name.to_string());
238        }
239        if let Some(name) = node_name {
240            if name == "If" {
241                Node::parse_if_view(input)
242            } else if name == "For" {
243                Node::parse_for_view(input)
244            } else {
245                Node::parse_user_view(name, input)
246            }
247        } else {
248            Err("unexpected start of view node".to_owned())
249        }
250    }
251
252    fn from(input: PeekableTokenStream) -> Result<Node, String> {
253        let (n, _) = Node::parse_view_node(input)?;
254        Ok(n)
255    }
256
257    fn compile_mods(&self) -> String {
258        if let Some(m) = &self.modifiers {
259            if m.len() == 0 {
260                "".to_owned()
261            } else {
262                m.iter()
263                    .map(|x| format!(r#"o.{}({});"#, x.function, x.parameters).to_string())
264                    .collect::<Vec<String>>()
265                    .join("\n")
266            }
267        } else {
268            "".to_owned()
269        }
270    }
271
272    fn compile_children(&self) -> String {
273        if let Some(c) = &self.children {
274            if c.len() == 0 {
275                return "None".to_owned();
276            }
277            let compiled_children = c
278                .iter()
279                .map(|x| match &x.node_type {
280                    NodeType::If(args) => {
281                        let if_children = x.compile_children();
282                        format!(
283                            r#"if {} {{ 
284                            c.append(&mut ({}).unwrap())
285                        }}"#,
286                            args, if_children
287                        )
288                        .to_string()
289                    }
290                    NodeType::For(args) => {
291                        let if_children = x.compile_children();
292                        format!(
293                            r#"for {} {{ 
294                            c.append(&mut ({}).unwrap());
295                        }}"#,
296                            args, if_children
297                        )
298                        .to_string()
299                    }
300                    _ => format!("c.push({});\n", x.compile()).to_owned(),
301                })
302                .collect::<Vec<String>>()
303                .join("\n");
304            return format!(
305                r#"{{
306                    let mut c = Vec::<View>::new();
307                    {}
308                    Some(c)
309                }}"#,
310                compiled_children
311            )
312            .to_owned();
313        }
314        "None".to_owned()
315    }
316
317    fn compile_user_node(&self) -> String {
318        let mods = self.compile_mods();
319        let compiled_children = self.compile_children();
320        match &self.node_type {
321            NodeType::Empty => format!(
322                r#"{{
323                        let mut o = {}{{..Default::default()}};
324                        {}
325                        o.construct({});
326                        View::{}(o)
327                    }}"#,
328                self.name, mods, compiled_children, self.name
329            )
330            .to_owned(),
331            NodeType::Params(args) => format!(
332                r#"{{
333                        let mut o = {}{{ {},..Default::default()}};
334                        {}
335                        o.construct({});
336                        View::{}(o)
337                    }}"#,
338                self.name, args, mods, compiled_children, self.name
339            )
340            .to_owned(),
341            NodeType::Simple(args) => format!(
342                r#"{{
343                        let mut o = {}::new({});
344                        {}
345                        o.construct({});
346                        View::{}(o)
347                    }}"#,
348                self.name, args, mods, compiled_children, self.name
349            )
350            .to_owned(),
351            _ => panic!("cannot start with non-user view"),
352        }
353    }
354
355    fn compile(&self) -> String {
356        match &self.node_type {
357            NodeType::Empty => self.compile_user_node(),
358            NodeType::Simple(_) => self.compile_user_node(),
359            NodeType::Params(_) => self.compile_user_node(),
360            _ => panic!("cannot start with non-user view"),
361        }
362    }
363}
364
365#[proc_macro_hack]
366pub fn view(input: TokenStream) -> TokenStream {
367    let tokens = input.into_iter().peekable();
368    let e = Node::from(tokens).expect("invalid syntax");
369    let s = e.compile();
370    TokenStream::from_str(&s).unwrap()
371}