Actually just three programming languages in a trenchcoat
at main 65 lines 2.0 kB view raw
1use crate::{Parser, Spanned}; 2use source_span::Span; 3use trilogy_scanner::Token; 4use trilogy_scanner::TokenType::{self, DocInner, DocOuter}; 5 6/// A documentation comment, either inner or outer. 7/// 8/// ```trilogy 9/// ## Hello this is a doc comment. 10/// ## It may be multiple lines long. 11/// ``` 12#[derive(Clone, Debug)] 13pub struct Documentation { 14 pub tokens: Vec<Token>, 15 pub span: Span, 16} 17 18impl Spanned for Documentation { 19 fn span(&self) -> Span { 20 self.span 21 } 22} 23 24impl Documentation { 25 fn parse(parser: &mut Parser, token_type: TokenType) -> Option<Self> { 26 let mut tokens = vec![]; 27 28 while let Ok(token) = parser.expect(token_type) { 29 tokens.push(token); 30 } 31 if tokens.is_empty() { 32 return None; 33 } 34 35 Some(Self { 36 span: tokens 37 .iter() 38 .map(|token| token.span) 39 .reduce(|l, r| l.union(r)) 40 .unwrap(), 41 tokens, 42 }) 43 } 44 45 pub(crate) fn parse_inner(parser: &mut Parser) -> Option<Self> { 46 Self::parse(parser, DocInner) 47 } 48 49 pub(crate) fn parse_outer(parser: &mut Parser) -> Option<Self> { 50 Self::parse(parser, DocOuter) 51 } 52} 53 54#[cfg(test)] 55mod test { 56 use super::*; 57 58 test_parse!(documentation_inner: "#! hello\n" => Documentation::parse_inner => Documentation { .. }); 59 test_parse!(documentation_inner_multiline: "#! hello\n#! world\n" => Documentation::parse_inner => Documentation { .. }); 60 test_parse!(documentation_inner_gaps: "#! hello\n\n#! world\n" => Documentation::parse_inner => Documentation { .. }); 61 62 test_parse!(documentation_outer: "## hello\n" => Documentation::parse_outer => Documentation { .. }); 63 test_parse!(documentation_outer_multiline: "## hello\n## world\n" => Documentation::parse_outer => Documentation { .. }); 64 test_parse!(documentation_outer_gaps: "## hello\n\n## world\n" => Documentation::parse_outer => Documentation { .. }); 65}