| use pest::iterators::Pairs; |
| use pest_meta::parser::Rule; |
| use std::collections::HashMap; |
| |
| #[derive(Debug)] |
| pub(crate) struct DocComment { |
| pub grammar_doc: String, |
| |
| /// HashMap for store all doc_comments for rules. |
| /// key is rule name, value is doc_comment. |
| pub line_docs: HashMap<String, String>, |
| } |
| |
| /// Consume pairs to matches `Rule::grammar_doc`, `Rule::line_doc` into `DocComment` |
| /// |
| /// e.g. |
| /// |
| /// a pest file: |
| /// |
| /// ```ignore |
| /// //! This is a grammar doc |
| /// /// line doc 1 |
| /// /// line doc 2 |
| /// foo = {} |
| /// |
| /// /// line doc 3 |
| /// bar = {} |
| /// ``` |
| /// |
| /// Then will get: |
| /// |
| /// ```ignore |
| /// grammar_doc = "This is a grammar doc" |
| /// line_docs = { "foo": "line doc 1\nline doc 2", "bar": "line doc 3" } |
| /// ``` |
| pub(crate) fn consume(pairs: Pairs<'_, Rule>) -> DocComment { |
| let mut grammar_doc = String::new(); |
| |
| let mut line_docs: HashMap<String, String> = HashMap::new(); |
| let mut line_doc = String::new(); |
| |
| for pair in pairs { |
| match pair.as_rule() { |
| Rule::grammar_doc => { |
| // grammar_doc > inner_doc |
| let inner_doc = pair.into_inner().next().unwrap(); |
| grammar_doc.push_str(inner_doc.as_str()); |
| grammar_doc.push('\n'); |
| } |
| Rule::grammar_rule => { |
| if let Some(inner) = pair.into_inner().next() { |
| // grammar_rule > line_doc | identifier |
| match inner.as_rule() { |
| Rule::line_doc => { |
| if let Some(inner_doc) = inner.into_inner().next() { |
| line_doc.push_str(inner_doc.as_str()); |
| line_doc.push('\n'); |
| } |
| } |
| Rule::identifier => { |
| if !line_doc.is_empty() { |
| let rule_name = inner.as_str().to_owned(); |
| |
| // Remove last \n |
| line_doc.pop(); |
| line_docs.insert(rule_name, line_doc.clone()); |
| line_doc.clear(); |
| } |
| } |
| _ => (), |
| } |
| } |
| } |
| _ => (), |
| } |
| } |
| |
| if !grammar_doc.is_empty() { |
| // Remove last \n |
| grammar_doc.pop(); |
| } |
| |
| DocComment { |
| grammar_doc, |
| line_docs, |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use std::collections::HashMap; |
| |
| use pest_meta::parser; |
| use pest_meta::parser::Rule; |
| |
| #[test] |
| fn test_doc_comment() { |
| let pairs = match parser::parse(Rule::grammar_rules, include_str!("../tests/test.pest")) { |
| Ok(pairs) => pairs, |
| Err(_) => panic!("error parsing tests/test.pest"), |
| }; |
| |
| let doc_comment = super::consume(pairs); |
| |
| let mut expected = HashMap::new(); |
| expected.insert("foo".to_owned(), "Matches foo str, e.g.: `foo`".to_owned()); |
| expected.insert( |
| "bar".to_owned(), |
| "Matches bar str\n\n Indent 2, e.g: `bar` or `foobar`".to_owned(), |
| ); |
| expected.insert( |
| "dar".to_owned(), |
| "Matches dar\n\nMatch dar description\n".to_owned(), |
| ); |
| assert_eq!(expected, doc_comment.line_docs); |
| |
| assert_eq!( |
| "A parser for JSON file.\nAnd this is a example for JSON parser.\n\n indent-4-space\n", |
| doc_comment.grammar_doc |
| ); |
| } |
| |
| #[test] |
| fn test_empty_grammar_doc() { |
| assert!(parser::parse(Rule::grammar_rules, "//!").is_ok()); |
| assert!(parser::parse(Rule::grammar_rules, "///").is_ok()); |
| assert!(parser::parse(Rule::grammar_rules, "//").is_ok()); |
| assert!(parser::parse(Rule::grammar_rules, "/// Line Doc").is_ok()); |
| assert!(parser::parse(Rule::grammar_rules, "//! Grammar Doc").is_ok()); |
| assert!(parser::parse(Rule::grammar_rules, "// Comment").is_ok()); |
| } |
| } |