blob: 6c9f6e2e60ceab78fa27426a6123ab1e98e97c00 [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) => {
7 tuple!($i, opt!(call!(::nom::multispace)), tag_s!($punct))
8 };
9}
10
11macro_rules! opt_vec (
12 ($i:expr, $submac:ident!( $($args:tt)* )) => ({
13 match $submac!($i, $($args)*) {
14 ::nom::IResult::Done(i, o) => ::nom::IResult::Done(i, o),
15 ::nom::IResult::Error(_) => ::nom::IResult::Done($i, Vec::new()),
16 ::nom::IResult::Incomplete(i) => ::nom::IResult::Incomplete(i)
17 }
18 });
19);
20
21macro_rules! epsilon {
22 ($i:expr,) => {
23 call!($i, {
24 fn epsilon<T>(input: T) -> ::nom::IResult<T, ()> {
25 ::nom::IResult::Done(input, ())
26 }
27 epsilon
28 })
29 };
30}
31
32pub fn escaped_string(input: &str) -> IResult<&str, String> {
33 let mut s = String::new();
34 let mut chars = input.char_indices().peekable();
35 while let Some((byte_offset, ch)) = chars.next() {
36 match ch {
37 '"' => {
38 return IResult::Done(&input[byte_offset..], s);
39 }
40 '\\' => {
41 match chars.next() {
42 Some((_, 'x')) => unimplemented!(),
43 Some((_, 'u')) => unimplemented!(),
44 Some((_, 'n')) => s.push('\n'),
45 Some((_, 'r')) => s.push('\r'),
46 Some((_, 't')) => s.push('\t'),
47 Some((_, '0')) => s.push('\0'),
48 Some((_, '\\')) => s.push('\\'),
49 Some((_, '\n')) => {
50 while let Some(&(_, ch)) = chars.peek() {
51 if ch.is_whitespace() {
52 chars.next();
53 } else {
54 break;
55 }
56 }
57 }
58 _ => break,
59 }
60 }
61 ch => {
62 s.push(ch);
63 }
64 }
65 }
66 IResult::Error(nom::Err::Position(nom::ErrorKind::Escaped, input))
67}