1use proc_macro2::{Span, TokenStream, TokenTree};
4use syn::{
5 braced,
6 ext::IdentExt,
7 parse::{discouraged::Speculative, Parse, ParseStream, Parser as _, Peek},
8 punctuated::Punctuated,
9 token::{Brace, Colon, Colon2},
10 Block, Error, Expr, ExprBlock, ExprLit, ExprPath, Ident, Path, PathSegment, Result, Token,
11};
12
13use crate::{node::*, punctuation::*};
14
15type TransformBlockFn = dyn Fn(ParseStream) -> Result<Option<TokenStream>>;
16
17#[derive(Default)]
19pub struct ParserConfig {
20 flat_tree: bool,
21 number_of_top_level_nodes: Option<usize>,
22 type_of_top_level_nodes: Option<NodeType>,
23 transform_block: Option<Box<TransformBlockFn>>,
24}
25
26impl ParserConfig {
27 pub fn new() -> ParserConfig {
29 ParserConfig::default()
30 }
31
32 pub fn flat_tree(mut self) -> Self {
34 self.flat_tree = true;
35 self
36 }
37
38 pub fn number_of_top_level_nodes(mut self, number: usize) -> Self {
40 self.number_of_top_level_nodes = Some(number);
41 self
42 }
43
44 pub fn type_of_top_level_nodes(mut self, node_type: NodeType) -> Self {
46 self.type_of_top_level_nodes = Some(node_type);
47 self
48 }
49
50 pub fn transform_block<F>(mut self, callback: F) -> Self
83 where
84 F: Fn(ParseStream) -> Result<Option<TokenStream>> + 'static,
85 {
86 self.transform_block = Some(Box::new(callback));
87 self
88 }
89}
90
91pub struct Parser {
93 config: ParserConfig,
94}
95
96impl Parser {
97 pub fn new(config: ParserConfig) -> Parser {
99 Parser { config }
100 }
101
102 pub fn parse(&self, input: ParseStream) -> Result<Vec<Node>> {
104 let mut nodes = vec![];
105 let mut top_level_nodes = 0;
106 while !input.cursor().eof() {
107 let parsed_nodes = &mut self.node(input)?;
108
109 if let Some(type_of_top_level_nodes) = &self.config.type_of_top_level_nodes {
110 if &parsed_nodes[0].node_type != type_of_top_level_nodes {
111 return Err(input.error(format!(
112 "top level nodes need to be of type {}",
113 type_of_top_level_nodes
114 )));
115 }
116 }
117
118 nodes.append(parsed_nodes);
119 top_level_nodes += 1;
120 }
121
122 if let Some(number_of_top_level_nodes) = &self.config.number_of_top_level_nodes {
123 if &top_level_nodes != number_of_top_level_nodes {
124 return Err(input.error(format!(
125 "saw {} top level nodes but exactly {} are required",
126 top_level_nodes, number_of_top_level_nodes
127 )));
128 }
129 }
130
131 Ok(nodes)
132 }
133
134 fn node(&self, input: ParseStream) -> Result<Vec<Node>> {
135 let node = if input.peek(Token![<]) {
136 if input.peek2(Token![!]) {
137 if input.peek3(Ident) {
138 self.doctype(input)
139 } else {
140 self.comment(input)
141 }
142 } else if input.peek2(Token![>]) {
143 self.fragment(input)
144 } else {
145 self.element(input)
146 }
147 } else if input.peek(Brace) {
148 self.block(input)
149 } else {
150 self.text(input)
151 }?;
152
153 let mut nodes = vec![node];
154 if self.config.flat_tree {
155 let mut children = vec![];
156 children.append(&mut nodes[0].children);
157 nodes.append(&mut children);
158 }
159
160 Ok(nodes)
161 }
162
163 fn text(&self, input: ParseStream) -> Result<Node> {
164 let text = input.parse::<ExprLit>()?.into();
165
166 Ok(Node {
167 name: None,
168 value: Some(text),
169 node_type: NodeType::Text,
170 attributes: vec![],
171 children: vec![],
172 })
173 }
174
175 fn block(&self, input: ParseStream) -> Result<Node> {
176 let block = if self.config.transform_block.is_some() {
177 self.block_transform(input)?
178 } else {
179 self.block_expr(input)?
180 };
181
182 Ok(Node {
183 name: None,
184 value: Some(block),
185 node_type: NodeType::Block,
186 attributes: vec![],
187 children: vec![],
188 })
189 }
190
191 fn block_transform(&self, input: ParseStream) -> Result<Expr> {
192 let transform_block = self.config.transform_block.as_ref().unwrap();
193
194 input.step(|cursor| {
195 if let Some((tree, next)) = cursor.token_tree() {
196 match tree {
197 TokenTree::Group(block_group) => {
198 let block_span = block_group.span();
199 let parser = move |block_content: ParseStream| match transform_block(
200 block_content,
201 ) {
202 Ok(transformed_tokens) => match transformed_tokens {
203 Some(tokens) => {
204 let parser = move |input: ParseStream| {
205 Ok(self.block_content_to_block(input, block_span))
206 };
207 parser.parse2(tokens)?
208 }
209 None => self.block_content_to_block(block_content, block_span),
210 },
211 Err(error) => Err(error),
212 };
213 Ok((parser.parse2(block_group.stream())?, next))
214 }
215 _ => Err(cursor.error("unexpected: no Group in TokenTree found")),
216 }
217 } else {
218 Err(cursor.error("unexpected: no TokenTree found"))
219 }
220 })
221 }
222
223 fn block_content_to_block(&self, input: ParseStream, span: Span) -> Result<Expr> {
224 Ok(ExprBlock {
225 attrs: vec![],
226 label: None,
227 block: Block {
228 brace_token: Brace { span },
229 stmts: Block::parse_within(input)?,
230 },
231 }
232 .into())
233 }
234
235 fn block_expr(&self, input: ParseStream) -> Result<Expr> {
236 let fork = input.fork();
237 let content;
238 let brace_token = braced!(content in fork);
239 let block = ExprBlock {
240 attrs: vec![],
241 label: None,
242 block: Block {
243 brace_token,
244 stmts: Block::parse_within(&content)?,
245 },
246 };
247 input.advance_to(&fork);
248
249 Ok(block.into())
250 }
251
252 fn element(&self, input: ParseStream) -> Result<Node> {
253 let fork = &input.fork();
254
255 if self.tag_close(&input.fork()).is_ok() {
256 return Err(fork.error("close tag has no corresponding open tag"));
257 }
258 let (name, attributes, self_closing) = self.tag_open(fork)?;
259
260 let mut children = vec![];
261 if !self_closing {
262 loop {
263 if !self.element_has_children(&name, fork)? {
264 break;
265 }
266
267 children.append(&mut self.node(fork)?);
268 }
269
270 self.tag_close(fork)?;
271 }
272 input.advance_to(fork);
273
274 Ok(Node {
275 name: Some(name),
276 value: None,
277 node_type: NodeType::Element,
278 attributes,
279 children,
280 })
281 }
282
283 fn element_has_children(&self, tag_open_name: &NodeName, input: ParseStream) -> Result<bool> {
284 if input.is_empty() {
286 return Err(Error::new(
287 tag_open_name.span(),
288 "open tag has no corresponding close tag and is not self-closing",
289 ));
290 }
291
292 if let Ok(tag_close_name) = self.tag_close(&input.fork()) {
293 if tag_open_name == &tag_close_name {
294 return Ok(false);
296 } else {
297 return Err(input.error("close tag has no corresponding open tag"));
299 }
300 }
301
302 Ok(true)
303 }
304
305 fn tag_open(&self, input: ParseStream) -> Result<(NodeName, Vec<Node>, bool)> {
306 input.parse::<Token![<]>()?;
307 let name = self.node_name(input)?;
308
309 let mut attributes = TokenStream::new();
310 let self_closing = loop {
311 if let Ok(self_closing) = self.tag_open_end(input) {
312 break self_closing;
313 }
314
315 if input.is_empty() {
316 return Err(input.error("expected closing caret >"));
317 }
318
319 let next: TokenTree = input.parse()?;
320 attributes.extend(Some(next));
321 };
322
323 let attributes = if !attributes.is_empty() {
324 let parser = move |input: ParseStream| self.attributes(input);
325 parser.parse2(attributes)?
326 } else {
327 vec![]
328 };
329
330 Ok((name, attributes, self_closing))
331 }
332
333 fn tag_open_end(&self, input: ParseStream) -> Result<bool> {
334 let self_closing = input.parse::<Option<Token![/]>>()?.is_some();
335 input.parse::<Token![>]>()?;
336
337 Ok(self_closing)
338 }
339
340 fn tag_close(&self, input: ParseStream) -> Result<NodeName> {
341 input.parse::<Token![<]>()?;
342 input.parse::<Token![/]>()?;
343 let name = self.node_name(input)?;
344 input.parse::<Token![>]>()?;
345
346 Ok(name)
347 }
348
349 fn attributes(&self, input: ParseStream) -> Result<Vec<Node>> {
350 let mut nodes = vec![];
351
352 loop {
353 if input.is_empty() {
354 break;
355 }
356
357 nodes.push(self.attribute(input)?);
358 }
359
360 Ok(nodes)
361 }
362
363 fn attribute(&self, input: ParseStream) -> Result<Node> {
364 let fork = &input.fork();
365 if fork.peek(Brace) {
366 let value = Some(self.block_expr(fork)?);
367 input.advance_to(fork);
368
369 Ok(Node {
370 name: None,
371 node_type: NodeType::Block,
372 value,
373 attributes: vec![],
374 children: vec![],
375 })
376 } else {
377 let key = self.node_name(fork)?;
378 let eq = fork.parse::<Option<Token![=]>>()?;
379 let value = if eq.is_some() {
380 if fork.is_empty() {
381 return Err(Error::new(key.span(), "missing attribute value"));
382 }
383
384 if fork.peek(Brace) {
385 Some(self.block_expr(fork)?)
386 } else {
387 Some(fork.parse()?)
388 }
389 } else {
390 None
391 };
392 input.advance_to(fork);
393
394 Ok(Node {
395 name: Some(key),
396 node_type: NodeType::Attribute,
397 value,
398 attributes: vec![],
399 children: vec![],
400 })
401 }
402 }
403
404 fn doctype(&self, input: ParseStream) -> Result<Node> {
405 input.parse::<Token![<]>()?;
406 input.parse::<Token![!]>()?;
407 let ident = input.parse::<Ident>()?;
408 if ident.to_string().to_lowercase() != "doctype" {
409 return Err(input.error("expected Doctype"));
410 }
411 let doctype = input.parse::<Ident>()?;
412 input.parse::<Token![>]>()?;
413
414 let mut segments = Punctuated::new();
415 segments.push_value(PathSegment::from(doctype));
416 let value = ExprPath {
417 attrs: vec![],
418 qself: None,
419 path: Path {
420 leading_colon: None,
421 segments,
422 },
423 }
424 .into();
425
426 Ok(Node {
427 name: None,
428 value: Some(value),
429 node_type: NodeType::Doctype,
430 attributes: vec![],
431 children: vec![],
432 })
433 }
434
435 fn comment(&self, input: ParseStream) -> Result<Node> {
436 input.parse::<Token![<]>()?;
437 input.parse::<Token![!]>()?;
438 input.parse::<Token![-]>()?;
439 input.parse::<Token![-]>()?;
440 let comment = input.parse::<ExprLit>()?.into();
441 input.parse::<Token![-]>()?;
442 input.parse::<Token![-]>()?;
443 input.parse::<Token![>]>()?;
444
445 Ok(Node {
446 name: None,
447 value: Some(comment),
448 node_type: NodeType::Comment,
449 attributes: vec![],
450 children: vec![],
451 })
452 }
453
454 fn fragment(&self, input: ParseStream) -> Result<Node> {
455 self.fragment_open(input)?;
456
457 let mut children = vec![];
458 loop {
459 if input.is_empty() {
460 return Err(input.error("unexpected end of input"));
461 }
462
463 if self.fragment_close(&input.fork()).is_ok() {
464 self.fragment_close(input)?;
465 break;
466 }
467
468 children.append(&mut self.node(input)?);
469 }
470
471 Ok(Node {
472 name: None,
473 value: None,
474 node_type: NodeType::Fragment,
475 attributes: vec![],
476 children,
477 })
478 }
479
480 fn fragment_open(&self, input: ParseStream) -> Result<()> {
481 input.parse::<Token![<]>()?;
482 input.parse::<Token![>]>()?;
483
484 Ok(())
485 }
486
487 fn fragment_close(&self, input: ParseStream) -> Result<()> {
488 input.parse::<Token![<]>()?;
489 input.parse::<Token![/]>()?;
490 input.parse::<Token![>]>()?;
491
492 Ok(())
493 }
494
495 fn node_name(&self, input: ParseStream) -> Result<NodeName> {
496 if input.peek2(Colon2) {
497 self.node_name_punctuated_ident::<Colon2, fn(_) -> Colon2, PathSegment>(input, Colon2)
498 .map(|segments| {
499 NodeName::Path(ExprPath {
500 attrs: vec![],
501 qself: None,
502 path: Path {
503 leading_colon: None,
504 segments,
505 },
506 })
507 })
508 } else if input.peek2(Colon) {
509 self.node_name_punctuated_ident::<Colon, fn(_) -> Colon, Ident>(input, Colon)
510 .map(NodeName::Colon)
511 } else if input.peek2(Dash) {
512 self.node_name_punctuated_ident::<Dash, fn(_) -> Dash, Ident>(input, Dash)
513 .map(NodeName::Dash)
514 } else if input.peek(Brace) {
515 let fork = &input.fork();
516 let value = self.block_expr(fork)?;
517 input.advance_to(fork);
518 Ok(NodeName::Block(value))
519 } else if input.peek(Ident::peek_any) {
520 let mut segments = Punctuated::new();
521 let ident = Ident::parse_any(input)?;
522 segments.push_value(PathSegment::from(ident));
523 Ok(NodeName::Path(ExprPath {
524 attrs: vec![],
525 qself: None,
526 path: Path {
527 leading_colon: None,
528 segments,
529 },
530 }))
531 } else {
532 Err(input.error("invalid tag name or attribute key"))
533 }
534 }
535
536 fn node_name_punctuated_ident<T: Parse, F: Peek, X: From<Ident>>(
542 &self,
543 input: ParseStream,
544 punct: F,
545 ) -> Result<Punctuated<X, T>> {
546 let fork = &input.fork();
547 let mut segments = Punctuated::<X, T>::new();
548
549 while !fork.is_empty() && fork.peek(Ident::peek_any) {
550 let ident = Ident::parse_any(fork)?;
551 segments.push_value(ident.clone().into());
552
553 if fork.peek(punct) {
554 segments.push_punct(fork.parse()?);
555 } else {
556 break;
557 }
558 }
559
560 if segments.len() > 1 {
561 input.advance_to(fork);
562 Ok(segments)
563 } else {
564 Err(fork.error("expected punctuated node name"))
565 }
566 }
567}