Split into modules
diff --git a/src/helper.rs b/src/helper.rs
new file mode 100644
index 0000000..5299cc4
--- /dev/null
+++ b/src/helper.rs
@@ -0,0 +1,65 @@
+use nom::{self, IResult};
+
+macro_rules! punct {
+ ($i:expr, $punct:expr) => {
+ tuple!($i, opt!(call!(::nom::multispace)), tag_s!($punct))
+ };
+}
+
+macro_rules! opt_vec (
+ ($i:expr, $submac:ident!( $($args:tt)* )) => ({
+ match $submac!($i, $($args)*) {
+ ::nom::IResult::Done(i, o) => ::nom::IResult::Done(i, o),
+ ::nom::IResult::Error(_) => ::nom::IResult::Done($i, Vec::new()),
+ ::nom::IResult::Incomplete(i) => ::nom::IResult::Incomplete(i)
+ }
+ });
+);
+
+macro_rules! epsilon {
+ ($i:expr,) => {
+ call!($i, {
+ fn epsilon<T>(input: T) -> ::nom::IResult<T, ()> {
+ ::nom::IResult::Done(input, ())
+ }
+ epsilon
+ })
+ };
+}
+
+pub fn escaped_string(input: &str) -> IResult<&str, String> {
+ let mut s = String::new();
+ let mut chars = input.char_indices().peekable();
+ while let Some((byte_offset, ch)) = chars.next() {
+ match ch {
+ '"' => {
+ return IResult::Done(&input[byte_offset..], s);
+ }
+ '\\' => {
+ match chars.next() {
+ Some((_, 'x')) => unimplemented!(),
+ Some((_, 'u')) => unimplemented!(),
+ Some((_, 'n')) => s.push('\n'),
+ Some((_, 'r')) => s.push('\r'),
+ Some((_, 't')) => s.push('\t'),
+ Some((_, '0')) => s.push('\0'),
+ Some((_, '\\')) => s.push('\\'),
+ Some((_, '\n')) => {
+ while let Some(&(_, ch)) = chars.peek() {
+ if ch.is_whitespace() {
+ chars.next();
+ } else {
+ break;
+ }
+ }
+ }
+ _ => break,
+ }
+ }
+ ch => {
+ s.push(ch);
+ }
+ }
+ }
+ IResult::Error(nom::Err::Position(nom::ErrorKind::Escaped, input))
+}