blob: 0e5cd89e0fbab2ff1e9f2bfb93039905b0f7f1dd [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
David Tolnay318195d2016-10-08 11:34:19 -07009 let bytes = input.as_bytes();
10 let mut i = 0;
11 while i < bytes.len() {
12 let s = &input[i..];
13 if bytes[i] == b'/' {
David Tolnaydaaf7742016-10-03 11:11:43 -070014 if s.starts_with("//") && (!s.starts_with("///") || s.starts_with("////")) &&
15 !s.starts_with("//!") {
David Tolnay14cbdeb2016-10-01 12:13:59 -070016 if let Some(len) = s.find('\n') {
David Tolnay318195d2016-10-08 11:34:19 -070017 i += len + 1;
David Tolnay14cbdeb2016-10-01 12:13:59 -070018 continue;
19 }
20 break;
David Tolnaydaaf7742016-10-03 11:11:43 -070021 } else if s.starts_with("/*") && !s.starts_with("/**") && !s.starts_with("/*!") {
David Tolnay14cbdeb2016-10-01 12:13:59 -070022 match block_comment(s) {
23 IResult::Done(_, com) => {
David Tolnay318195d2016-10-08 11:34:19 -070024 i += com.len();
David Tolnay14cbdeb2016-10-01 12:13:59 -070025 continue;
26 }
27 IResult::Error => {
28 return IResult::Error;
29 }
30 }
31 }
32 }
David Tolnay318195d2016-10-08 11:34:19 -070033 match bytes[i] {
34 b' ' | 0x09...0x0d => {
35 i += 1;
36 continue;
37 }
David Tolnay3bcfb722016-10-08 11:58:36 -070038 b if b <= 0x7f => {}
David Tolnay318195d2016-10-08 11:34:19 -070039 _ => {
40 let ch = s.chars().next().unwrap();
41 if ch.is_whitespace() {
42 i += ch.len_utf8();
43 continue;
44 }
45 }
David Tolnay14cbdeb2016-10-01 12:13:59 -070046 }
David Tolnay318195d2016-10-08 11:34:19 -070047 return if i > 0 {
48 IResult::Done(s, ())
49 } else {
50 IResult::Error
51 };
David Tolnay14cbdeb2016-10-01 12:13:59 -070052 }
53 IResult::Done("", ())
54}
55
56pub fn block_comment(input: &str) -> IResult<&str, &str> {
57 if !input.starts_with("/*") {
58 return IResult::Error;
59 }
60
61 let mut depth = 0;
David Tolnay079b5ad2016-10-08 09:39:29 -070062 let bytes = input.as_bytes();
63 let mut i = 0;
64 let upper = bytes.len() - 1;
65 while i < upper {
66 if bytes[i] == b'/' && bytes[i + 1] == b'*' {
David Tolnay14cbdeb2016-10-01 12:13:59 -070067 depth += 1;
David Tolnay079b5ad2016-10-08 09:39:29 -070068 i += 1; // eat '*'
69 } else if bytes[i] == b'*' && bytes[i + 1] == b'/' {
David Tolnay14cbdeb2016-10-01 12:13:59 -070070 depth -= 1;
71 if depth == 0 {
72 return IResult::Done(&input[i + 2..], &input[..i + 2]);
73 }
David Tolnay079b5ad2016-10-08 09:39:29 -070074 i += 1; // eat '/'
David Tolnay14cbdeb2016-10-01 12:13:59 -070075 }
David Tolnay079b5ad2016-10-08 09:39:29 -070076 i += 1;
David Tolnay14cbdeb2016-10-01 12:13:59 -070077 }
78 IResult::Error
79}
80
81pub fn word_break(input: &str) -> IResult<&str, ()> {
82 match input.chars().next() {
David Tolnaydaaf7742016-10-03 11:11:43 -070083 Some(ch) if UnicodeXID::is_xid_continue(ch) => IResult::Error,
84 Some(_) | None => IResult::Done(input, ()),
David Tolnay14cbdeb2016-10-01 12:13:59 -070085 }
86}
David Tolnaydef66372016-10-24 21:51:32 -070087
88pub fn skip_whitespace(input: &str) -> &str {
89 match whitespace(input) {
90 IResult::Done(rest, _) => rest,
91 IResult::Error => input,
92 }
93}