blob: a97fbee39e8ce9e65c11aa1443f92055bf560983 [file] [log] [blame]
David Tolnay86eca752016-09-04 11:26:41 -07001#![cfg(feature = "parsing")]
2
David Tolnayb79ee962016-09-04 09:39:20 -07003use nom::{self, IResult};
4
5macro_rules! punct {
6 ($i:expr, $punct:expr) => {
David Tolnay13e5da42016-09-04 16:18:34 -07007 $crate::helper::punct($i, $punct)
David Tolnayb79ee962016-09-04 09:39:20 -07008 };
9}
10
David Tolnay13e5da42016-09-04 16:18:34 -070011pub fn punct<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, &'a str> {
12 let mut chars = input.char_indices();
13 while let Some((i, ch)) = chars.next() {
14 if !ch.is_whitespace() {
15 return if input[i..].starts_with(token) {
16 let end = i + token.len();
17 IResult::Done(&input[end..], &input[i..end])
18 } else {
19 IResult::Error(nom::Err::Position(nom::ErrorKind::TagStr, input))
20 };
21 }
22 }
23 IResult::Error(nom::Err::Position(nom::ErrorKind::TagStr, input))
24}
25
David Tolnayf6ccb832016-09-04 15:00:56 -070026macro_rules! option (
27 ($i:expr, $submac:ident!( $($args:tt)* )) => ({
28 match $submac!($i, $($args)*) {
29 ::nom::IResult::Done(i, o) => ::nom::IResult::Done(i, Some(o)),
30 ::nom::IResult::Error(_) => ::nom::IResult::Done($i, None),
31 ::nom::IResult::Incomplete(_) => ::nom::IResult::Done($i, None),
32 }
33 });
34 ($i:expr, $f:expr) => (
35 option!($i, call!($f));
36 );
37);
38
David Tolnayb79ee962016-09-04 09:39:20 -070039macro_rules! opt_vec (
40 ($i:expr, $submac:ident!( $($args:tt)* )) => ({
41 match $submac!($i, $($args)*) {
42 ::nom::IResult::Done(i, o) => ::nom::IResult::Done(i, o),
43 ::nom::IResult::Error(_) => ::nom::IResult::Done($i, Vec::new()),
David Tolnayf6ccb832016-09-04 15:00:56 -070044 ::nom::IResult::Incomplete(_) => ::nom::IResult::Done($i, Vec::new()),
David Tolnayb79ee962016-09-04 09:39:20 -070045 }
46 });
47);
48
49macro_rules! epsilon {
50 ($i:expr,) => {
51 call!($i, {
52 fn epsilon<T>(input: T) -> ::nom::IResult<T, ()> {
53 ::nom::IResult::Done(input, ())
54 }
55 epsilon
56 })
57 };
58}
59
60pub fn escaped_string(input: &str) -> IResult<&str, String> {
61 let mut s = String::new();
62 let mut chars = input.char_indices().peekable();
63 while let Some((byte_offset, ch)) = chars.next() {
64 match ch {
65 '"' => {
66 return IResult::Done(&input[byte_offset..], s);
67 }
68 '\\' => {
69 match chars.next() {
70 Some((_, 'x')) => unimplemented!(),
71 Some((_, 'u')) => unimplemented!(),
72 Some((_, 'n')) => s.push('\n'),
73 Some((_, 'r')) => s.push('\r'),
74 Some((_, 't')) => s.push('\t'),
75 Some((_, '0')) => s.push('\0'),
76 Some((_, '\\')) => s.push('\\'),
77 Some((_, '\n')) => {
78 while let Some(&(_, ch)) = chars.peek() {
79 if ch.is_whitespace() {
80 chars.next();
81 } else {
82 break;
83 }
84 }
85 }
86 _ => break,
87 }
88 }
89 ch => {
90 s.push(ch);
91 }
92 }
93 }
94 IResult::Error(nom::Err::Position(nom::ErrorKind::Escaped, input))
95}