1 | //! Type and helper to collect the gramamr and rule documentation. |
2 | |
3 | use pest::iterators::Pairs; |
4 | use pest_meta::parser::Rule; |
5 | use std::collections::HashMap; |
6 | |
7 | /// Abstraction for the grammer and rule doc. |
8 | #[derive (Debug)] |
9 | pub struct DocComment { |
10 | /// The grammar documentation is defined at the beginning of a file with //!. |
11 | pub grammar_doc: String, |
12 | |
13 | /// HashMap for store all doc_comments for rules. |
14 | /// key is rule name, value is doc_comment. |
15 | pub line_docs: HashMap<String, String>, |
16 | } |
17 | |
18 | /// Consume pairs to matches `Rule::grammar_doc`, `Rule::line_doc` into `DocComment` |
19 | /// |
20 | /// e.g. |
21 | /// |
22 | /// a pest file: |
23 | /// |
24 | /// ```ignore |
25 | /// //! This is a grammar doc |
26 | /// /// line doc 1 |
27 | /// /// line doc 2 |
28 | /// foo = {} |
29 | /// |
30 | /// /// line doc 3 |
31 | /// bar = {} |
32 | /// ``` |
33 | /// |
34 | /// Then will get: |
35 | /// |
36 | /// ```ignore |
37 | /// grammar_doc = "This is a grammar doc" |
38 | /// line_docs = { "foo" : "line doc 1 \nline doc 2" , "bar" : "line doc 3" } |
39 | /// ``` |
40 | pub fn consume(pairs: Pairs<'_, Rule>) -> DocComment { |
41 | let mut grammar_doc = String::new(); |
42 | |
43 | let mut line_docs: HashMap<String, String> = HashMap::new(); |
44 | let mut line_doc = String::new(); |
45 | |
46 | for pair in pairs { |
47 | match pair.as_rule() { |
48 | Rule::grammar_doc => { |
49 | // grammar_doc > inner_doc |
50 | let inner_doc = pair.into_inner().next().unwrap(); |
51 | grammar_doc.push_str(inner_doc.as_str()); |
52 | grammar_doc.push(' \n' ); |
53 | } |
54 | Rule::grammar_rule => { |
55 | if let Some(inner) = pair.into_inner().next() { |
56 | // grammar_rule > line_doc | identifier |
57 | match inner.as_rule() { |
58 | Rule::line_doc => { |
59 | if let Some(inner_doc) = inner.into_inner().next() { |
60 | line_doc.push_str(inner_doc.as_str()); |
61 | line_doc.push(' \n' ); |
62 | } |
63 | } |
64 | Rule::identifier => { |
65 | if !line_doc.is_empty() { |
66 | let rule_name = inner.as_str().to_owned(); |
67 | |
68 | // Remove last \n |
69 | line_doc.pop(); |
70 | line_docs.insert(rule_name, line_doc.clone()); |
71 | line_doc.clear(); |
72 | } |
73 | } |
74 | _ => (), |
75 | } |
76 | } |
77 | } |
78 | _ => (), |
79 | } |
80 | } |
81 | |
82 | if !grammar_doc.is_empty() { |
83 | // Remove last \n |
84 | grammar_doc.pop(); |
85 | } |
86 | |
87 | DocComment { |
88 | grammar_doc, |
89 | line_docs, |
90 | } |
91 | } |
92 | |
93 | #[cfg (test)] |
94 | mod tests { |
95 | use std::collections::HashMap; |
96 | |
97 | use pest_meta::parser; |
98 | use pest_meta::parser::Rule; |
99 | |
100 | #[test ] |
101 | fn test_doc_comment() { |
102 | let pairs = match parser::parse(Rule::grammar_rules, include_str!("../tests/test.pest" )) { |
103 | Ok(pairs) => pairs, |
104 | Err(_) => panic!("error parsing tests/test.pest" ), |
105 | }; |
106 | |
107 | let doc_comment = super::consume(pairs); |
108 | |
109 | let mut expected = HashMap::new(); |
110 | expected.insert("foo" .to_owned(), "Matches foo str, e.g.: `foo`" .to_owned()); |
111 | expected.insert( |
112 | "bar" .to_owned(), |
113 | "Matches bar str \n\n Indent 2, e.g: `bar` or `foobar`" .to_owned(), |
114 | ); |
115 | expected.insert( |
116 | "dar" .to_owned(), |
117 | "Matches dar \n\nMatch dar description \n" .to_owned(), |
118 | ); |
119 | assert_eq!(expected, doc_comment.line_docs); |
120 | |
121 | assert_eq!( |
122 | "A parser for JSON file. \nAnd this is a example for JSON parser. \n\n indent-4-space \n" , |
123 | doc_comment.grammar_doc |
124 | ); |
125 | } |
126 | |
127 | #[test ] |
128 | fn test_empty_grammar_doc() { |
129 | assert!(parser::parse(Rule::grammar_rules, "//!" ).is_ok()); |
130 | assert!(parser::parse(Rule::grammar_rules, "///" ).is_ok()); |
131 | assert!(parser::parse(Rule::grammar_rules, "//" ).is_ok()); |
132 | assert!(parser::parse(Rule::grammar_rules, "/// Line Doc" ).is_ok()); |
133 | assert!(parser::parse(Rule::grammar_rules, "//! Grammar Doc" ).is_ok()); |
134 | assert!(parser::parse(Rule::grammar_rules, "// Comment" ).is_ok()); |
135 | } |
136 | } |
137 | |