lemmy_help/parser/
node.rs

1use chumsky::{
2    prelude::{any, choice, Simple},
3    select, Parser, Stream,
4};
5
6use crate::{
7    lexer::{Lexer, TagType},
8    parser::{Alias, Brief, Class, Divider, Func, Module, Tag, Type},
9    Accept, Visitor,
10};
11
12use super::impl_parse;
13
14#[derive(Debug, Clone)]
15pub enum Node {
16    Module(Module),
17    Divider(Divider),
18    Brief(Brief),
19    Tag(Tag),
20    Func(Func),
21    Class(Class),
22    Alias(Alias),
23    Type(Type),
24    Export(String),
25    Toc(String),
26}
27
28impl_parse!(Node, Option<Self>, {
29    choice((
30        Module::parse().map(Self::Module),
31        Divider::parse().map(Self::Divider),
32        Brief::parse().map(Self::Brief),
33        Tag::parse().map(Self::Tag),
34        Func::parse().map(Self::Func),
35        Class::parse().map(Self::Class),
36        Alias::parse().map(Self::Alias),
37        Type::parse().map(Self::Type),
38        select! {
39            TagType::Export(x) => Self::Export(x),
40            TagType::Toc(x) => Self::Toc(x),
41        },
42    ))
43    .map(Some)
44    // Skip useless nodes
45    .or(any().to(None))
46});
47
48impl<T: Visitor> Accept<T> for Node {
49    fn accept(&self, n: &T, s: &T::S) -> T::R {
50        match self {
51            Self::Brief(x) => x.accept(n, s),
52            Self::Tag(x) => x.accept(n, s),
53            Self::Alias(x) => x.accept(n, s),
54            Self::Func(x) => x.accept(n, s),
55            Self::Class(x) => x.accept(n, s),
56            Self::Type(x) => x.accept(n, s),
57            Self::Module(x) => x.accept(n, s),
58            Self::Divider(x) => x.accept(n, s),
59            _ => unimplemented!(),
60        }
61    }
62}
63
64impl Node {
65    fn init() -> impl Parser<TagType, Vec<Node>, Error = Simple<TagType>> {
66        Node::parse().repeated().flatten()
67    }
68
69    /// Creates stream of AST nodes from emmylua
70    ///
71    /// ```
72    /// let src = r#"
73    /// local U = {}
74    ///
75    /// ---Add two integar and print it
76    /// ---@param this number First number
77    /// ---@param that number Second number
78    /// function U.sum(this, that)
79    ///     print(this + that)
80    /// end
81    ///
82    /// return U
83    /// "#;
84    ///
85    /// let nodes = lemmy_help::parser::Node::new(src).unwrap();
86    /// assert!(!nodes.is_empty());
87    /// ```
88    pub fn new(src: &str) -> Result<Vec<Node>, Vec<Simple<TagType>>> {
89        let tokens = Lexer::init().parse(src).unwrap();
90        let stream = Stream::from_iter(src.len()..src.len() + 1, tokens.into_iter());
91
92        Node::init().parse(stream)
93    }
94}