aidl_parser/
javadoc.rs

1pub fn get_javadoc(input: &str, pos: usize) -> Option<String> {
2    find_content_string(&input[..pos]).map(parse_javadoc)
3}
4fn find_content_string(input: &str) -> Option<&str> {
5    let mut pos = 0;
6    let mut start_pos: Option<usize> = None;
7    let mut end_pos: Option<usize> = None;
8
9    enum FindState {
10        Idle,
11        LineCommentOrSomethingElse,
12        LineCommentOrSomethingElseBeforeSlash,
13        BeforeEndSlash,
14        InsideComment,
15        BeforeBeginStar,
16        BeforeBeginStarStar,
17    }
18
19    let mut state = FindState::Idle;
20
21    for current in input.chars().rev() {
22        pos += 1;
23        match state {
24            FindState::Idle => {
25                if current == '/' {
26                    state = FindState::BeforeEndSlash;
27                } else if current != ' ' && current != '\n' && current != '\r' && current != '\t' {
28                    state = FindState::LineCommentOrSomethingElse;
29                }
30            }
31            FindState::LineCommentOrSomethingElse => {
32                if current == '/' {
33                    state = FindState::LineCommentOrSomethingElseBeforeSlash;
34                } else if current == '\n' {
35                    break;
36                }
37            }
38            FindState::LineCommentOrSomethingElseBeforeSlash => {
39                if current == '/' {
40                    state = FindState::Idle;
41                } else {
42                    break;
43                }
44            }
45            FindState::BeforeEndSlash => {
46                state = if current == '*' {
47                    end_pos = Some(pos);
48                    FindState::InsideComment
49                } else {
50                    FindState::Idle
51                };
52            }
53            FindState::InsideComment => {
54                if current == '*' {
55                    state = FindState::BeforeBeginStar;
56                };
57            }
58            FindState::BeforeBeginStar => {
59                state = if current == '*' {
60                    FindState::BeforeBeginStarStar
61                } else if current == '/' {
62                    FindState::Idle
63                } else {
64                    FindState::InsideComment
65                };
66            }
67            FindState::BeforeBeginStarStar => {
68                if current == '/' {
69                    start_pos = Some(pos - 3);
70                    break;
71                }
72
73                state = FindState::InsideComment;
74            }
75        }
76    }
77
78    match (start_pos, end_pos) {
79        (Some(start_pos), Some(end_pos)) => {
80            let start_pos = input.len() - start_pos;
81            let end_pos = input.len() - end_pos;
82
83            Some(&input[start_pos..end_pos])
84        }
85        _ => None,
86    }
87}
88
89fn parse_javadoc(s: &str) -> String {
90    // Transform into vec
91    let re = regex::Regex::new("\r?\n[ \t*]*\r?\n").unwrap();
92    let lines = re.split(s);
93
94    // Remove begin/end noise of each line
95    let re = regex::Regex::new("[ \t\r\n*]*\n[ \t\r\n*]*").unwrap();
96    let lines = lines.map(|s| {
97        let s = s.trim_matches(|c| c == '\r' || c == '\n' || c == ' ' || c == '\t' || c == '*');
98        re.replace_all(s, " ").to_string()
99    });
100
101    // Add \n before @
102    let re = regex::Regex::new("([^\n])[ \t]*@").unwrap();
103    let lines = lines.map(|s| re.replace_all(&s, "${1}\n@").to_string());
104
105    lines.collect::<Vec<_>>().join("\n")
106}
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111
112    #[test]
113    fn test_find_content_string() {
114        let input = "/**TestJavaDoc*/";
115        assert_eq!(find_content_string(input), Some("TestJavaDoc"));
116
117        let input = r#"bla bla
118            /**
119             * TestJavaDoc
120             * 
121             * End
122             */
123             // Comment"#;
124        assert_eq!(
125            find_content_string(input),
126            Some(
127                r#"
128             * TestJavaDoc
129             * 
130             * End
131             "#
132            )
133        );
134
135        let input = r#"
136            /** Documentation before */
137            /** The real documentation */
138            /* Comment after */
139            // Line comment after
140            "#;
141        assert_eq!(find_content_string(input), Some(" The real documentation "),);
142
143        let input = r#"
144            /** Other documentation */
145            something else;
146            "#;
147        assert_eq!(find_content_string(input), None);
148
149        let input = r#"
150            something else;
151            /**The documentation*/
152            "#;
153        assert_eq!(find_content_string(input), Some("The documentation"));
154    }
155
156    #[test]
157    fn test_parse_javadoc() {
158        let input = "This is a javadoc\n * comment";
159        assert_eq!(parse_javadoc(input), "This is a javadoc comment");
160
161        let input = "\n * JavaDoc title\n *\n * JavaDoc text1\n * JavaDoc text2\n";
162        assert_eq!(
163            parse_javadoc(input),
164            "JavaDoc title\nJavaDoc text1 JavaDoc text2"
165        );
166
167        let input = r#"
168                * JavaDoc title
169                * @param Param1 Description
170                * @param Param2 Description
171                *
172                * Description
173                "#;
174        assert_eq!(
175            parse_javadoc(input),
176            "JavaDoc title\n@param Param1 Description\n@param Param2 Description\nDescription"
177        );
178    }
179}