1use proc_macro2::{Delimiter, TokenStream, TokenTree};
2use syn::{
3 braced,
4 buffer::Cursor,
5 parse::{Parse, ParseBuffer, ParseStream},
6 token::Brace,
7 Expr, Ident, LitStr, Result, Token,
8};
9
10use crate::{data_types::stack::Stack, enums::html_element::HtmlElement};
11
12pub mod to_tokens;
13
14pub fn parse(item: TokenStream) -> Result<Html> {
15 Ok(syn::parse2(item.into())?)
16}
17
18#[derive(Clone, Debug)]
19pub struct Html {
20 children: Vec<Html>,
21 value: Lex,
22}
23
24impl Html {
25 pub fn children(&self) -> &Vec<Html> {
26 &self.children
27 }
28
29 pub fn value(&self) -> &Lex {
30 &self.value
31 }
32}
33
34impl Parse for Html {
35 fn parse(input: ParseStream) -> Result<Self> {
36 let mut stack: Stack<Html> = Stack::new();
37
38 stack.push(Html {
39 children: vec![],
40 value: Lex::Tag {
41 element: HtmlElement::Fragment,
42 attributes: vec![],
43 },
44 });
45
46 while !input.is_empty() {
47 if input.peek(Token![<]) && input.peek2(Ident) {
48 input.parse::<Token![<]>()?;
49 let element: HtmlElement = input.parse()?;
50 let mut attrs: Vec<Attribute> = vec![];
51
52 while !(input.peek(Token![>]) || input.peek(Token![/])) {
53 if input.peek(Ident)
54 || input.peek(Token![type])
55 || input.peek(Token![async])
56 || input.peek(Token![for])
57 {
58 let attr: Attribute = input.parse()?;
59 attrs.push(attr);
60 }
61
62 if input.is_empty() {
63 return Err(syn::Error::new(
64 input.span(),
65 "Unexpected end of input in start tag",
66 ));
67 }
68
69 if input.peek(Token![<]) {
70 return Err(syn::Error::new(input.span(), "< shouldn't be here"));
71 }
72 }
73
74 if input.peek(Token![/]) {
75 input.parse::<Token![/]>()?;
76 }
77
78 input.parse::<Token![>]>()?;
79
80 let tag = Html {
81 children: vec![],
82 value: Lex::Tag {
83 element: element.clone(),
84 attributes: attrs,
85 },
86 };
87
88 if element.is_void() {
89 if let Some(mut parent) = stack.pop() {
90 parent.children.push(tag);
91 stack.push(parent);
92 } else {
93 stack.push(tag);
94 }
95 } else {
96 stack.push(tag);
97 }
98 } else if input.peek(Token![<]) && input.peek2(Token![/]) && input.peek3(Ident) {
99 input.parse::<Token![<]>()?;
100 input.parse::<Token![/]>()?;
101
102 let el: HtmlElement = input.parse()?;
103
104 let previous1 = if let Some(previous1) = stack.pop() {
105 previous1
106 } else {
107 return Err(syn::Error::new(
108 input.span(),
109 &format!("There is no opening tag for </{}>", &el.to_string()),
110 ));
111 };
112
113 if let Lex::Tag { element, .. } = &previous1.value {
114 if element.to_string() == el.to_string() {
115 if let Some(mut previous2) = stack.pop() {
116 previous2.children.push(previous1);
117 stack.push(previous2);
118 } else {
119 return Err(syn::Error::new(
120 input.span(),
121 "A single root is mandatory.",
122 ));
123 }
124 } else {
125 return Err(syn::Error::new(input.span(), "Invalid syntax"));
126 }
127 }
128
129 input.parse::<Token![>]>()?;
130 } else if input.peek(Brace) {
131 let content;
132 braced!(content in input);
133
134 if !content.peek(Brace) {
135 let sanitized_var = Self::extract_variable(&content)?;
136
137 if let Some(mut parent) = stack.pop() {
138 parent.children.push(Html {
139 children: vec![],
140 value: Lex::SanitizedVar(sanitized_var),
141 });
142 stack.push(parent);
143 } else {
144 return Err(syn::Error::new(input.span(), "A single root is mandatory"));
145 }
146 } else {
147 let var;
148 braced!(var in content);
149
150 let var = Self::extract_variable(&var)?;
151
152 if let Some(mut parent) = stack.pop() {
153 parent.children.push(Html {
154 children: vec![],
155 value: Lex::Var(var),
156 });
157 stack.push(parent);
158 } else {
159 return Err(syn::Error::new(input.span(), "A single root is mandatory"));
160 }
161 }
162 } else if input.peek(Token![if]) {
163 input.parse::<Token![if]>()?;
164
165 let condition = Self::extract_condition(input)?;
166
167 let body;
168 braced!(body in input);
169 let body: ParseStream = &body;
170
171 let body: Html = Self::parse(&body)?;
172
173 if let Some(mut previous) = stack.pop() {
174 previous.children.push(Html {
175 children: vec![body],
176 value: Lex::If(condition.to_string()),
177 });
178 stack.push(previous);
179 } else {
180 return Err(syn::Error::new(
181 input.span(),
182 "`if` should be used inside of a node",
183 ));
184 }
185 } else if input.peek(Token![else]) && input.peek2(Token![if]) {
186 input.parse::<Token![else]>()?;
187 input.parse::<Token![if]>()?;
188
189 let condition = Self::extract_condition(input)?;
190
191 let body;
192 braced!(body in input);
193 let body: ParseStream = &body;
194
195 let body: Html = Self::parse(&body)?;
196
197 if let Some(mut previous) = stack.pop() {
198 previous.children.push(Html {
199 children: vec![body],
200 value: Lex::ElseIf(condition.to_string()),
201 });
202 stack.push(previous);
203 } else {
204 return Err(syn::Error::new(
205 input.span(),
206 "`else-if` should be used inside of a node",
207 ));
208 }
209 } else if input.peek(Token![else]) {
210 input.parse::<Token![else]>()?;
211
212 let body;
213 braced!(body in input);
214 let body: ParseStream = &body;
215
216 let body: Html = Self::parse(&body)?;
217
218 if let Some(mut previous) = stack.pop() {
219 previous.children.push(Html {
220 children: vec![body],
221 value: Lex::Else,
222 });
223 stack.push(previous);
224 } else {
225 return Err(syn::Error::new(
226 input.span(),
227 "`else` should be used inside of a node",
228 ));
229 }
230 } else if input.peek(Token![for]) {
231 input.parse::<Token![for]>()?;
232
233 let var: Ident = input.parse()?;
234
235 input.parse::<Token![in]>()?;
236
237 let iter = Self::extract_iter(input)?;
238
239 let body;
240 braced!(body in input);
241 let body: ParseStream = &body;
242
243 let body: Html = Self::parse(&body)?;
244
245 if let Some(mut previous) = stack.pop() {
246 previous.children.push(Html {
247 children: vec![body],
248 value: Lex::For {
249 var: var.to_string(),
250 iter: iter.to_string(),
251 },
252 });
253 stack.push(previous);
254 } else {
255 return Err(syn::Error::new(
256 input.span(),
257 "`for-in` should be used inside of a node",
258 ));
259 }
260 } else if input.peek(Token![<]) && input.peek2(Token![!]) && input.peek3(Ident) {
261 input.parse::<Token![<]>()?;
262 input.parse::<Token![!]>()?;
263
264 let ident: Ident = input.parse()?;
265 let doc_type: Ident = input.parse()?;
266
267 if ident.to_string().to_uppercase() != "DOCTYPE"
268 || doc_type.to_string().to_lowercase() != "html"
269 {
270 return Err(syn::Error::new(
271 input.span(),
272 "`DOCTYPE html` is expected following by `!`",
273 ));
274 }
275
276 input.parse::<Token![>]>()?;
277
278 if let Some(mut previous) = stack.pop() {
279 previous.children.push(Html {
280 children: vec![],
281 value: Lex::DocType,
282 });
283 stack.push(previous);
284 } else {
285 return Err(syn::Error::new(
286 input.span(),
287 "A single root is mandatory. DOCTYPE cannot be a parent node.",
288 ));
289 }
290 } else {
291 return Err(syn::Error::new(input.span(), "Invalid token"));
292 }
293 }
294
295 if stack.len != 1 {
296 return Err(syn::Error::new(
297 input.span(),
298 "Error: lack of some closing tags",
299 ));
300 }
301
302 let root = if let Some(root) = stack.pop() {
303 root
304 } else {
305 return Err(syn::Error::new(input.span(), "There is no root tag"));
306 };
307
308 Ok(root)
309 }
310}
311
312impl Html {
313 fn extract_variable(input: &ParseBuffer) -> Result<String> {
314 let variable = input.step(|cursor| {
315 let result: Result<(String, Cursor)> = {
316 let mut rest = *cursor;
317 let mut tokens = String::new();
318
319 while let Some((tt, next)) = rest.token_tree() {
320 tokens += &tt.to_string();
321 rest = next;
322 }
323
324 Ok((tokens, rest))
325 };
326
327 result
328 })?;
329
330 Ok(variable)
331 }
332
333 fn extract_iter(input: ParseStream) -> Result<TokenStream> {
334 let iter = input.step(|cursor| {
335 let result: Result<(TokenStream, Cursor)> = {
336 let mut rest = *cursor;
337 let mut tokens: Vec<TokenTree> = vec![];
338
339 while let Some((tt, next)) = rest.token_tree() {
340 if let TokenTree::Group(g) = &tt {
341 if g.delimiter() == Delimiter::Brace {
342 return Ok((tokens.into_iter().collect(), rest));
343 }
344 }
345
346 tokens.push(tt);
347 rest = next;
348 }
349
350 if tokens.is_empty() {
351 Err(syn::Error::new(input.span(), "Iter should be here."))
352 } else {
353 Ok((tokens.into_iter().collect(), *cursor))
354 }
355 };
356
357 result
358 });
359
360 iter
361 }
362
363 fn extract_condition(input: ParseStream) -> Result<TokenStream> {
364 let condition = input.step(|cursor| {
365 let result: Result<(TokenStream, Cursor)> = {
366 let mut rest = *cursor;
367 let mut tokens: Vec<TokenTree> = vec![];
368
369 while let Some((tt, next)) = rest.token_tree() {
370 if let TokenTree::Group(g) = &tt {
371 if g.delimiter() == Delimiter::Brace {
372 return Ok((tokens.into_iter().collect(), rest));
373 }
374 }
375
376 tokens.push(tt);
377 rest = next;
378 }
379
380 if tokens.is_empty() {
381 Err(syn::Error::new(input.span(), "Condition shuold be here."))
382 } else {
383 Ok((tokens.into_iter().collect(), *cursor))
384 }
385 };
386
387 result
388 });
389
390 condition
391 }
392}
393
394#[derive(Clone, Debug)]
395pub enum Lex {
396 Tag {
397 element: HtmlElement,
398 attributes: Vec<Attribute>,
399 },
400 DocType,
401 SanitizedVar(String),
402 Var(String),
403 If(String),
404 ElseIf(String),
405 Else,
406 For {
407 var: String,
408 iter: String,
409 },
410}
411
412#[derive(Debug, Clone)]
413pub struct Attribute(String, Option<AttributeValue>);
414
415#[derive(Debug, Clone)]
416pub enum AttributeValue {
417 Text(String),
418 Var(Expr),
419}
420
421impl Parse for Attribute {
422 fn parse(input: ParseStream) -> Result<Self> {
423 let key = if input.peek(Ident) {
424 let key: Ident = input.parse()?;
425 let mut key = key.to_string();
426
427 while input.peek(Token![-]) {
428 input.parse::<Token![-]>()?;
429 key += "-";
430
431 if input.peek(Ident) {
432 key += &input.parse::<Ident>()?.to_string();
433 } else if input.peek(Token![async]) {
434 input.parse::<Token![async]>()?;
435 key += "async";
436 } else if input.peek(Token![type]) {
437 input.parse::<Token![type]>()?;
438 key += "type";
439 } else if input.peek(Token![for]) {
440 input.parse::<Token![for]>()?;
441 key += "for";
442 } else {
443 return Err(syn::Error::new(input.span(), "Cannot be used as attribute"));
444 }
445 }
446
447 key
448 } else if input.peek(Token![async]) {
449 input.parse::<Token![async]>()?;
450 "async".to_string()
451 } else if input.peek(Token![type]) {
452 input.parse::<Token![type]>()?;
453 "type".to_string()
454 } else if input.peek(Token![for]) {
455 input.parse::<Token![for]>()?;
456 "for".to_string()
457 } else {
458 return Err(syn::Error::new(
459 input.span(),
460 "Some attributes should be here.",
461 ));
462 };
463
464 if input.peek(Token![=]) {
465 input.parse::<Token![=]>()?;
466
467 if input.peek(Brace) {
468 let mut value;
469 braced!(value in input);
470 braced!(value in value);
471 let value: Expr = value.parse()?;
472 return Ok(Attribute(key, Some(AttributeValue::Var(value))));
473 }
474
475 let value: LitStr = input.parse()?;
476 return Ok(Attribute(key, Some(AttributeValue::Text(value.value()))));
477 } else {
478 Ok(Attribute(key, None))
479 }
480 }
481}
482
483impl Attribute {
484 pub fn key(&self) -> &str {
485 &self.0
486 }
487 pub fn value(&self) -> &Option<AttributeValue> {
488 &self.1
489 }
490}