1use std::vec;
4
5use proc_macro2::{Punct, Span, TokenStream, TokenTree};
6use syn::{
7 braced,
8 ext::IdentExt,
9 parse::{discouraged::Speculative, Parse, ParseStream, Parser as _, Peek},
10 punctuated::Punctuated,
11 spanned::Spanned,
12 token::{Brace, Colon, Colon2},
13 Block, Error, Expr, ExprBlock, ExprLit, ExprPath, Ident, Path, PathSegment, Result, Token,
14};
15
16use crate::{config::TransformBlockFn, node::*, punctuation::*, ParserConfig};
17
18pub struct Parser {
20 config: ParserConfig,
21}
22
23impl Parser {
24 pub fn new(config: ParserConfig) -> Parser {
26 Parser { config }
27 }
28
29 pub fn parse(&self, input: ParseStream) -> Result<Vec<Node>> {
31 let mut nodes = vec![];
32 let mut top_level_nodes = 0;
33 while !input.cursor().eof() {
34 let mut parsed_nodes = self.node(input)?;
35
36 if let Some(type_of_top_level_nodes) = &self.config.type_of_top_level_nodes {
37 if &parsed_nodes[0].r#type() != type_of_top_level_nodes {
38 return Err(input.error(format!(
39 "top level nodes need to be of type {}",
40 type_of_top_level_nodes
41 )));
42 }
43 }
44
45 top_level_nodes += 1;
46 nodes.append(&mut parsed_nodes);
47 }
48
49 if let Some(number_of_top_level_nodes) = &self.config.number_of_top_level_nodes {
50 if &top_level_nodes != number_of_top_level_nodes {
51 return Err(input.error(format!(
52 "saw {} top level nodes but exactly {} are required",
53 top_level_nodes, number_of_top_level_nodes
54 )));
55 }
56 }
57
58 Ok(nodes)
59 }
60
61 fn node(&self, input: ParseStream) -> Result<Vec<Node>> {
66 let mut node = if input.peek(Token![<]) {
67 if input.peek2(Token![!]) {
68 if input.peek3(Ident) {
69 self.doctype(input)
70 } else {
71 self.comment(input)
72 }
73 } else if input.peek2(Token![>]) {
74 self.fragment(input)
75 } else {
76 self.element(input)
77 }
78 } else if input.peek(Brace) {
79 self.block(input)
80 } else {
81 self.text(input)
82 }?;
83
84 if self.config.flat_tree {
85 let mut children = node
86 .children_mut()
87 .map(|children| children.drain(..))
88 .into_iter()
89 .flatten()
90 .collect::<Vec<_>>();
91
92 let mut nodes = vec![node];
93 nodes.append(&mut children);
94 Ok(nodes)
95 } else {
96 Ok(vec![node])
97 }
98 }
99
100 fn text(&self, input: ParseStream) -> Result<Node> {
102 let value = input.parse::<ExprLit>()?.into();
103
104 Ok(Node::Text(NodeText { value }))
105 }
106
107 fn block(&self, input: ParseStream) -> Result<Node> {
109 let value = if let Some(transform_fn) = &self.config.transform_block {
110 self.block_transform(input, transform_fn)?
111 } else {
112 self.block_expr(input)?
113 }
114 .into();
115
116 Ok(Node::Block(NodeBlock { value }))
117 }
118
119 fn block_transform(&self, input: ParseStream, transform_fn: &TransformBlockFn) -> Result<Expr> {
123 let parser = move |block_content: ParseStream| {
124 let forked_block_content = block_content.fork();
125
126 match transform_fn(&forked_block_content) {
127 Ok(transformed_tokens) => match transformed_tokens {
128 Some(tokens) => {
129 let parser = move |input: ParseStream| {
130 Ok(self.block_content_to_block(input, block_content.span()))
131 };
132 let transformed_content = parser.parse2(tokens)?;
133 block_content.advance_to(&forked_block_content);
134 transformed_content
135 }
136 None => self.block_content_to_block(block_content, block_content.span()),
137 },
138 Err(error) => Err(error),
139 }
140 };
141
142 input.step(|cursor| {
143 let (tree, next) = cursor
144 .token_tree()
145 .ok_or_else(|| cursor.error("unexpected: no TokenTree found"))?;
146
147 match tree {
148 TokenTree::Group(block_group) => Ok((parser.parse2(block_group.stream())?, next)),
149 _ => Err(cursor.error("unexpected: no Group in TokenTree found")),
150 }
151 })
152 }
153
154 fn block_content_to_block(&self, input: ParseStream, span: Span) -> Result<Expr> {
156 Ok(ExprBlock {
157 attrs: vec![],
158 label: None,
159 block: Block {
160 brace_token: Brace { span },
161 stmts: Block::parse_within(input)?,
162 },
163 }
164 .into())
165 }
166
167 fn block_expr(&self, input: ParseStream) -> Result<Expr> {
169 let fork = input.fork();
170 let content;
171 let brace_token = braced!(content in fork);
172 let block = ExprBlock {
173 attrs: vec![],
174 label: None,
175 block: Block {
176 brace_token,
177 stmts: Block::parse_within(&content)?,
178 },
179 };
180 input.advance_to(&fork);
181
182 Ok(block.into())
183 }
184
185 fn element(&self, input: ParseStream) -> Result<Node> {
187 let fork = &input.fork();
188
189 if self.tag_close(&input.fork()).is_ok() {
190 return Err(fork.error("close tag has no corresponding open tag"));
191 }
192 let (name, attributes, self_closing) = self.tag_open(fork)?;
193
194 let mut children = vec![];
195 if !self_closing {
196 loop {
197 if !self.element_has_children(&name, fork)? {
198 break;
199 }
200
201 children.append(&mut self.node(fork)?);
202 }
203
204 self.tag_close(fork)?;
205 }
206 input.advance_to(fork);
207
208 Ok(Node::Element(NodeElement {
209 name,
210 attributes,
211 children,
212 }))
213 }
214
215 fn element_has_children(&self, tag_open_name: &NodeName, input: ParseStream) -> Result<bool> {
218 if input.is_empty() {
220 return Err(Error::new(
221 tag_open_name.span(),
222 "open tag has no corresponding close tag and is not self-closing",
223 ));
224 }
225
226 if let Ok(tag_close_name) = self.tag_close(&input.fork()) {
227 if tag_open_name == &tag_close_name {
228 return Ok(false);
230 } else {
231 return Err(input.error("close tag has no corresponding open tag"));
234 }
235 }
236
237 Ok(true)
238 }
239
240 fn tag_open(&self, input: ParseStream) -> Result<(NodeName, Vec<Node>, bool)> {
243 input.parse::<Token![<]>()?;
244 let name = self.node_name(input)?;
245
246 let mut attributes = TokenStream::new();
247 let self_closing = loop {
248 if let Ok(self_closing) = self.tag_open_end(input) {
249 break self_closing;
250 }
251
252 if input.is_empty() {
253 return Err(input.error("expected closing caret >"));
254 }
255
256 let next: TokenTree = input.parse()?;
257 attributes.extend(Some(next));
258 };
259
260 let attributes = if !attributes.is_empty() {
261 let parser = move |input: ParseStream| self.attributes(input);
262 parser.parse2(attributes)?
263 } else {
264 vec![]
265 };
266
267 Ok((name, attributes, self_closing))
268 }
269
270 fn tag_open_end(&self, input: ParseStream) -> Result<bool> {
272 let self_closing = input.parse::<Option<Token![/]>>()?.is_some();
273 input.parse::<Token![>]>()?;
274
275 Ok(self_closing)
276 }
277
278 fn tag_close(&self, input: ParseStream) -> Result<NodeName> {
280 input.parse::<Token![<]>()?;
281 input.parse::<Token![/]>()?;
282 let name = self.node_name(input)?;
283 input.parse::<Token![>]>()?;
284
285 Ok(name)
286 }
287
288 fn attributes(&self, input: ParseStream) -> Result<Vec<Node>> {
290 let mut nodes = vec![];
291
292 loop {
293 if input.is_empty() {
294 break;
295 }
296
297 nodes.push(self.attribute(input)?);
298 }
299
300 Ok(nodes)
301 }
302
303 fn attribute(&self, input: ParseStream) -> Result<Node> {
305 let fork = &input.fork();
306 if fork.peek(Brace) {
307 let value = self.block_expr(fork)?.into();
308 input.advance_to(fork);
309
310 Ok(Node::Block(NodeBlock { value }))
311 } else {
312 let key = self.node_name(fork)?;
313 let eq = fork.parse::<Option<Token![=]>>()?;
314 let value = if eq.is_some() {
315 if fork.is_empty() {
316 return Err(Error::new(key.span(), "missing attribute value"));
317 }
318
319 if fork.peek(Brace) {
320 Some(NodeValueExpr::new(self.block_expr(fork)?))
321 } else {
322 Some(NodeValueExpr::new(fork.parse()?))
323 }
324 } else {
325 None
326 };
327 input.advance_to(fork);
328
329 Ok(Node::Attribute(NodeAttribute { key, value }))
330 }
331 }
332
333 fn doctype(&self, input: ParseStream) -> Result<Node> {
335 input.parse::<Token![<]>()?;
336 input.parse::<Token![!]>()?;
337 let ident = input.parse::<Ident>()?;
338 if ident.to_string().to_lowercase() != "doctype" {
339 return Err(input.error("expected Doctype"));
340 }
341 let doctype = input.parse::<Ident>()?;
342 input.parse::<Token![>]>()?;
343
344 let mut segments = Punctuated::new();
345 segments.push_value(PathSegment::from(doctype));
346 let value = NodeValueExpr::new(
347 ExprPath {
348 attrs: vec![],
349 qself: None,
350 path: Path {
351 leading_colon: None,
352 segments,
353 },
354 }
355 .into(),
356 );
357
358 Ok(Node::Doctype(NodeDoctype { value }))
359 }
360
361 fn comment(&self, input: ParseStream) -> Result<Node> {
363 input.parse::<Token![<]>()?;
364 input.parse::<Token![!]>()?;
365 input.parse::<Token![-]>()?;
366 input.parse::<Token![-]>()?;
367 let value = NodeValueExpr::new(input.parse::<ExprLit>()?.into());
368 input.parse::<Token![-]>()?;
369 input.parse::<Token![-]>()?;
370 input.parse::<Token![>]>()?;
371
372 Ok(Node::Comment(NodeComment { value }))
373 }
374
375 fn fragment(&self, input: ParseStream) -> Result<Node> {
377 self.fragment_open(input)?;
378
379 let mut children = vec![];
380 loop {
381 if input.is_empty() {
382 return Err(input.error("unexpected end of input"));
383 }
384
385 if self.fragment_close(&input.fork()).is_ok() {
386 self.fragment_close(input)?;
387 break;
388 }
389
390 children.append(&mut self.node(input)?);
391 }
392
393 Ok(Node::Fragment(NodeFragment { children }))
394 }
395
396 fn fragment_open(&self, input: ParseStream) -> Result<()> {
398 input.parse::<Token![<]>()?;
399 input.parse::<Token![>]>()?;
400
401 Ok(())
402 }
403
404 fn fragment_close(&self, input: ParseStream) -> Result<()> {
406 input.parse::<Token![<]>()?;
407 input.parse::<Token![/]>()?;
408 input.parse::<Token![>]>()?;
409
410 Ok(())
411 }
412
413 fn node_name(&self, input: ParseStream) -> Result<NodeName> {
415 if input.peek2(Colon2) {
416 self.node_name_punctuated_ident::<Colon2, fn(_) -> Colon2, PathSegment>(input, Colon2)
417 .map(|segments| {
418 NodeName::Path(ExprPath {
419 attrs: vec![],
420 qself: None,
421 path: Path {
422 leading_colon: None,
423 segments,
424 },
425 })
426 })
427 } else if input.peek2(Colon) || input.peek2(Dash) {
428 self.node_name_punctuated_ident_with_alternate::<Punct, fn(_) -> Colon, fn(_) -> Dash, Ident>(
429 input, Colon, Dash,
430 )
431 .map(NodeName::Punctuated)
432 } else if input.peek(Brace) {
433 let fork = &input.fork();
434 let value = self.block_expr(fork)?;
435 input.advance_to(fork);
436 Ok(NodeName::Block(value))
437 } else if input.peek(Ident::peek_any) {
438 let mut segments = Punctuated::new();
439 let ident = Ident::parse_any(input)?;
440 segments.push_value(PathSegment::from(ident));
441 Ok(NodeName::Path(ExprPath {
442 attrs: vec![],
443 qself: None,
444 path: Path {
445 leading_colon: None,
446 segments,
447 },
448 }))
449 } else {
450 Err(input.error("invalid tag name or attribute key"))
451 }
452 }
453
454 fn node_name_punctuated_ident<T: Parse, F: Peek, X: From<Ident>>(
462 &self,
463 input: ParseStream,
464 punct: F,
465 ) -> Result<Punctuated<X, T>> {
466 let fork = &input.fork();
467 let mut segments = Punctuated::<X, T>::new();
468
469 while !fork.is_empty() && fork.peek(Ident::peek_any) {
470 let ident = Ident::parse_any(fork)?;
471 segments.push_value(ident.clone().into());
472
473 if fork.peek(punct) {
474 segments.push_punct(fork.parse()?);
475 } else {
476 break;
477 }
478 }
479
480 if segments.len() > 1 {
481 input.advance_to(fork);
482 Ok(segments)
483 } else {
484 Err(fork.error("expected punctuated node name"))
485 }
486 }
487
488 fn node_name_punctuated_ident_with_alternate<T: Parse, F: Peek, G: Peek, X: From<Ident>>(
491 &self,
492 input: ParseStream,
493 punct: F,
494 alternate_punct: G,
495 ) -> Result<Punctuated<X, T>> {
496 let fork = &input.fork();
497 let mut segments = Punctuated::<X, T>::new();
498
499 while !fork.is_empty() && fork.peek(Ident::peek_any) {
500 let ident = Ident::parse_any(fork)?;
501 segments.push_value(ident.clone().into());
502
503 if fork.peek(punct) || fork.peek(alternate_punct) {
504 segments.push_punct(fork.parse()?);
505 } else {
506 break;
507 }
508 }
509
510 if segments.len() > 1 {
511 input.advance_to(fork);
512 Ok(segments)
513 } else {
514 Err(fork.error("expected punctuated node name"))
515 }
516 }
517}