blob: 5536df4e9feb938e20ab7b9de84868cf824d5af5 [file] [log] [blame]
David Tolnay14cbdeb2016-10-01 12:13:59 -07001use nom::IResult;
2use unicode_xid::UnicodeXID;
3
4pub fn whitespace(input: &str) -> IResult<&str, ()> {
5 if input.is_empty() {
6 return IResult::Error;
7 }
8
9 let mut start = 0;
10 let mut chars = input.char_indices();
11 while let Some((i, ch)) = chars.next() {
12 let s = &input[start + i..];
13 if ch == '/' {
14 if s.starts_with("//")
15 && (!s.starts_with("///") || s.starts_with("////"))
16 && !s.starts_with("//!") {
17 if let Some(len) = s.find('\n') {
18 start += i + len + 1;
19 chars = input[start..].char_indices();
20 continue;
21 }
22 break;
23 } else if s.starts_with("/*")
24 && !s.starts_with("/**")
25 && !s.starts_with("/*!") {
26 match block_comment(s) {
27 IResult::Done(_, com) => {
28 start += i + com.len();
29 chars = input[start..].char_indices();
30 continue;
31 }
32 IResult::Error => {
33 return IResult::Error;
34 }
35 }
36 }
37 }
38 if !ch.is_whitespace() {
39 return if start + i > 0 {
40 IResult::Done(s, ())
41 } else {
42 IResult::Error
43 };
44 }
45 }
46 IResult::Done("", ())
47}
48
49pub fn block_comment(input: &str) -> IResult<&str, &str> {
50 if !input.starts_with("/*") {
51 return IResult::Error;
52 }
53
54 let mut depth = 0;
55 let mut chars = input.char_indices();
56 while let Some((i, _)) = chars.next() {
57 let s = &input[i..];
58 if s.starts_with("/*") {
59 depth += 1;
60 chars.next(); // eat '*'
61 } else if s.starts_with("*/") {
62 depth -= 1;
63 if depth == 0 {
64 return IResult::Done(&input[i + 2..], &input[..i + 2]);
65 }
66 chars.next(); // eat '/'
67 }
68 }
69 IResult::Error
70}
71
72pub fn word_break(input: &str) -> IResult<&str, ()> {
73 match input.chars().next() {
74 Some(ch) if UnicodeXID::is_xid_continue(ch) => {
75 IResult::Error
76 }
77 Some(_) | None => {
78 IResult::Done(input, ())
79 }
80 }
81}