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