1extern crate proc_macro;
2use proc_macro_hack::proc_macro_hack;
3use proc_macro::{Delimiter, TokenStream, TokenTree};
4use 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}