//! Parsers and helper functions operating on strings, especially useful when writing parsers for
//! text-based formats.

/// `tag_s!(&str) => &str -> IResult<&str, &str>`
/// declares a string as a suite to recognize
///
/// consumes the recognized characters
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult;
/// # fn main() {
///  fn test(input: &str) -> IResult<&str, &str> {
///    tag_s!(input, "abcd")
///  }
///  let r = test("abcdefgh");
///  assert_eq!(r,Ok(("efgh", "abcd")));
/// # }
/// ```
#[macro_export(local_inner_macros)]
#[deprecated(since = "4.0.0", note = "Please use `tag` instead")]
macro_rules! tag_s (
  ($i:expr, $tag: expr) => (
    {
      tag!($i, $tag)
    }
  );
);

/// `tag_no_case_s!(&str) => &str -> IResult<&str, &str>`
/// declares a case-insensitive string as a suite to recognize
///
/// consumes the recognized characters
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult;
/// # use nom::InputLength;
/// #[cfg(feature = "alloc")]
/// # fn main() {
///  fn test(input: &str) -> IResult<&str, &str> {
///    tag_no_case_s!(input, "ABcd")
///  }
///  let r = test("aBCdefgh");
///  assert_eq!(r,Ok(("efgh", "aBCd")));
/// # }
/// # #[cfg(not(feature = "alloc"))]
/// # fn main() {}
/// ```
#[macro_export(local_inner_macros)]
#[deprecated(since = "4.0.0", note = "Please use `tag_no_case` instead")]
macro_rules! tag_no_case_s (
  ($i:expr, $tag: expr) => (
    {
      tag_no_case!($i, $tag)
    }
  );
);

/// `take_s!(nb) => &str -> IResult<&str, &str>`
/// generates a parser consuming the specified number of characters
///
/// ```
/// # #[macro_use] extern crate nom;
/// # fn main() {
///  // Desmond parser
///  named!(take5<&str,&str>, take_s!( 5 ) );
///
///  let a = "abcdefgh";
///
///  assert_eq!(take5(a),Ok(("fgh", "abcde")));
///
///  let b = "12345";
///
///  assert_eq!(take5(b),Ok(("", "12345")));
/// # }
/// ```
#[macro_export(local_inner_macros)]
#[deprecated(since = "4.0.0", note = "Please use `take` instead")]
macro_rules! take_s (
  ($i:expr, $count:expr) => (
    {
      let input = $i;
      let cnt = $count as usize;
      take!(input, cnt)
    }
  );
);

/// `is_not_s!(&str) => &str -> IResult<&str, &str>`
/// returns the longest list of characters that do not appear in the provided array
///
/// ```
/// # #[macro_use] extern crate nom;
/// # fn main() {
///  named!( not_space<&str,&str>, is_not_s!( " \t\r\n" ) );
///
///  let r = not_space("abcdefgh\nijkl");
///  assert_eq!(r,Ok(("\nijkl", "abcdefgh")));
///  # }
/// ```
#[macro_export(local_inner_macros)]
#[deprecated(since = "4.0.0", note = "Please use `is_not` instead")]
macro_rules! is_not_s (
  ($input:expr, $arr:expr) => (
    {
      is_not!($input, $arr)
    }
  );
);

/// `is_a_s!(&str) => &str -> IResult<&str, &str>`
/// returns the longest list of characters that appear in the provided array
///
/// ```
/// # #[macro_use] extern crate nom;
/// # fn main() {
///  named!(abcd<&str, &str>, is_a_s!( "abcd" ));
///
///  let r1 = abcd("aaaaefgh");
///  assert_eq!(r1,Ok(("efgh", "aaaa")));
///
///  let r2 = abcd("dcbaefgh");
///  assert_eq!(r2,Ok(("efgh", "dcba")));
/// # }
/// ```
#[macro_export(local_inner_macros)]
#[deprecated(since = "4.0.0", note = "Please use `is_a` instead")]
macro_rules! is_a_s (
  ($input:expr, $arr:expr) => (
    {
      is_a!($input, $arr)
    }
  );
);

/// `take_while_s!(char -> bool) => &str -> IResult<&str, &str>`
/// returns the longest list of characters until the provided function fails.
///
/// The argument is either a function `char -> bool` or a macro returning a `bool
///
/// ```
/// # #[macro_use] extern crate nom;
/// # fn main() {
///  fn alphabetic(chr: char) -> bool { (chr >= 0x41 as char && chr <= 0x5A as char) || (chr >= 0x61 as char && chr <= 0x7A as char) }
///  named!( alpha<&str,&str>, take_while_s!( alphabetic ) );
///
///  let r = alpha("abcd\nefgh");
///  assert_eq!(r,Ok(("\nefgh", "abcd")));
/// # }
/// ```
#[macro_export(local_inner_macros)]
#[deprecated(since = "4.0.0", note = "Please use `take_while` instead")]
macro_rules! take_while_s (
  ($input:expr, $submac:ident!( $($args:tt)* )) => (
    {
      take_while!($input, $submac!($($args)*))
    }
  );
  ($input:expr, $f:expr) => (
    take_while_s!($input, call!($f));
  );
);

/// `take_while1_s!(char -> bool) => &str -> IResult<&str, &str>`
/// returns the longest (non empty) list of characters until the provided function fails.
///
/// The argument is either a function `char -> bool` or a macro returning a `bool`
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::is_alphanumeric;
/// # fn main() {
///  fn alphabetic(chr: char) -> bool { (chr >= 0x41 as char && chr <= 0x5A as char) || (chr >= 0x61 as char && chr <= 0x7A as char) }
///  named!( alpha<&str,&str>, take_while1_s!( alphabetic ) );
///
///  let r = alpha("abcd\nefgh");
///  assert_eq!(r, Ok(("\nefgh", "abcd")));
/// # }
/// ```
#[macro_export(local_inner_macros)]
#[deprecated(since = "4.0.0", note = "Please use `take_while1` instead")]
macro_rules! take_while1_s (
  ($input:expr, $submac:ident!( $($args:tt)* )) => (
    take_while1!($input, $submac!($($args)*))
  );
  ($input:expr, $f:expr) => (
    take_while1_s!($input, call!($f));
  );
);

/// `take_till_s!(char -> bool) => &str -> IResult<&str, &str>`
/// returns the longest list of characters until the provided function succeeds
///
/// The argument is either a function `char -> bool` or a macro returning a `bool
#[macro_export(local_inner_macros)]
#[deprecated(since = "4.0.0", note = "Please use `take_till` instead")]
macro_rules! take_till_s (
  ($input:expr, $submac:ident!( $($args:tt)* )) => (
    {
      take_till!($input, $submac!($($args)*))
    }
  );
  ($input:expr, $f:expr) => (
    take_till_s!($input, call!($f));
  );
);

/// `take_till1_s!(char -> bool) => &str -> IResult<&str, &str>`
/// returns the longest non empty list of characters until the provided function succeeds
///
/// The argument is either a function `char -> bool` or a macro returning a `bool
#[macro_export(local_inner_macros)]
#[deprecated(since = "4.0.0", note = "Please use `take_till1` instead")]
macro_rules! take_till1_s (
  ($input:expr, $submac:ident!( $($args:tt)* )) => (
    {
      take_till1!($input, $submac!($($args)*))
    }
  );
  ($input:expr, $f:expr) => (
    take_till1_s!($input, call!($f));
  );
);

/// `take_until_and_consume_s!(&str) => &str -> IResult<&str, &str>`
/// generates a parser consuming all chars until the specified string is found and consumes it
#[macro_export(local_inner_macros)]
#[deprecated(since = "4.0.0", note = "Please use `take_until_and_consume` instead")]
macro_rules! take_until_and_consume_s (
  ($input:expr, $substr:expr) => (
    {
      take_until_and_consume!($input, $substr)
    }
  );
);

/// `take_until_s!(&str) => &str -> IResult<&str, &str>`
/// generates a parser consuming all chars until the specified string is found and leaves it in the remaining input
#[macro_export(local_inner_macros)]
#[deprecated(since = "4.0.0", note = "Please use `take_until` instead")]
macro_rules! take_until_s (
  ($input:expr, $substr:expr) => (
    {
      take_until!($input, $substr)
    }
  );
);

#[cfg(test)]
mod test {
  use {Err, ErrorKind, IResult};

  #[test]
  fn tag_str_succeed() {
    const INPUT: &str = "Hello World!";
    const TAG: &str = "Hello";
    fn test(input: &str) -> IResult<&str, &str> {
      tag_s!(input, TAG)
    }

    match test(INPUT) {
      Ok((extra, output)) => {
        assert!(
          extra == " World!",
          "Parser `tag_s` consumed leftover input."
        );
        assert!(
          output == TAG,
          "Parser `tag_s` doesn't return the tag it matched on success. \
           Expected `{}`, got `{}`.",
          TAG,
          output
        );
      }
      other => panic!(
        "Parser `tag_s` didn't succeed when it should have. \
         Got `{:?}`.",
        other
      ),
    };
  }

  #[test]
  fn tag_str_incomplete() {
    const INPUT: &str = "Hello";
    const TAG: &str = "Hello World!";

    match tag_s!(INPUT, TAG) {
      Err(Err::Incomplete(_)) => (),
      other => {
        panic!(
          "Parser `tag_s` didn't require more input when it should have. \
           Got `{:?}`.",
          other
        );
      }
    };
  }

  #[test]
  fn tag_str_error() {
    const INPUT: &str = "Hello World!";
    const TAG: &str = "Random"; // TAG must be closer than INPUT.

    match tag_s!(INPUT, TAG) {
      Err(Err::Error(_)) => (),
      other => {
        panic!(
          "Parser `tag_s` didn't fail when it should have. Got `{:?}`.`",
          other
        );
      }
    };
  }

  #[test]
  fn take_s_succeed() {
    const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
    const CONSUMED: &str = "βèƒôřèÂßÇ";
    const LEFTOVER: &str = "áƒƭèř";

    match take_s!(INPUT, 9) {
      Ok((extra, output)) => {
        assert!(
          extra == LEFTOVER,
          "Parser `take_s` consumed leftover input. Leftover `{}`.",
          extra
        );
        assert!(
          output == CONSUMED,
          "Parser `take_s` doens't return the string it consumed on success. Expected `{}`, got `{}`.",
          CONSUMED,
          output
        );
      }
      other => panic!(
        "Parser `take_s` didn't succeed when it should have. \
         Got `{:?}`.",
        other
      ),
    };
  }

  #[test]
  fn take_until_s_succeed() {
    const INPUT: &str = "βèƒôřèÂßÇ∂áƒƭèř";
    const FIND: &str = "ÂßÇ∂";
    const CONSUMED: &str = "βèƒôřè";
    const LEFTOVER: &str = "ÂßÇ∂áƒƭèř";

    match take_until_s!(INPUT, FIND) {
      Ok((extra, output)) => {
        assert!(
          extra == LEFTOVER,
          "Parser `take_until_s`\
           consumed leftover input. Leftover `{}`.",
          extra
        );
        assert!(
          output == CONSUMED,
          "Parser `take_until_s`\
           doens't return the string it consumed on success. Expected `{}`, got `{}`.",
          CONSUMED,
          output
        );
      }
      other => panic!(
        "Parser `take_until_s` didn't succeed when it should have. \
         Got `{:?}`.",
        other
      ),
    };
  }

  #[test]
  fn take_s_incomplete() {
    const INPUT: &str = "βèƒôřèÂßÇá";

    match take_s!(INPUT, 13) {
      Err(Err::Incomplete(_)) => (),
      other => panic!(
        "Parser `take_s` didn't require more input when it should have. \
         Got `{:?}`.",
        other
      ),
    }
  }

  use internal::Needed;

  pub fn is_alphabetic(c: char) -> bool {
    (c as u8 >= 0x41 && c as u8 <= 0x5A) || (c as u8 >= 0x61 && c as u8 <= 0x7A)
  }
  #[test]
  fn take_while_s() {
    named!(f<&str,&str>, take_while_s!(is_alphabetic));
    let a = "";
    let b = "abcd";
    let c = "abcd123";
    let d = "123";

    assert_eq!(f(&a[..]), Err(Err::Incomplete(Needed::Size(1))));
    assert_eq!(f(&b[..]), Err(Err::Incomplete(Needed::Size(1))));
    assert_eq!(f(&c[..]), Ok((&d[..], &b[..])));
    assert_eq!(f(&d[..]), Ok((&d[..], &a[..])));
  }

  #[test]
  fn take_while1_s() {
    named!(f<&str,&str>, take_while1_s!(is_alphabetic));
    let a = "";
    let b = "abcd";
    let c = "abcd123";
    let d = "123";

    assert_eq!(f(&a[..]), Err(Err::Incomplete(Needed::Size(1))));
    assert_eq!(f(&b[..]), Err(Err::Incomplete(Needed::Size(1))));
    assert_eq!(f(&c[..]), Ok((&"123"[..], &b[..])));
    assert_eq!(
      f(&d[..]),
      Err(Err::Error(error_position!(&d[..], ErrorKind::TakeWhile1)))
    );
  }

  #[test]
  fn take_till_s_succeed() {
    const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
    const CONSUMED: &str = "βèƒôřèÂßÇ";
    const LEFTOVER: &str = "áƒƭèř";
    fn till_s(c: char) -> bool {
      c == 'á'
    }
    fn test(input: &str) -> IResult<&str, &str> {
      take_till_s!(input, till_s)
    }
    match test(INPUT) {
      Ok((extra, output)) => {
        assert!(
          extra == LEFTOVER,
          "Parser `take_till_s` consumed leftover input."
        );
        assert!(
          output == CONSUMED,
          "Parser `take_till_s` doesn't return the string it consumed on success. \
           Expected `{}`, got `{}`.",
          CONSUMED,
          output
        );
      }
      other => panic!(
        "Parser `take_till_s` didn't succeed when it should have. \
         Got `{:?}`.",
        other
      ),
    };
  }

  #[test]
  fn take_while_s_succeed_none() {
    const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
    const CONSUMED: &str = "";
    const LEFTOVER: &str = "βèƒôřèÂßÇáƒƭèř";
    fn while_s(c: char) -> bool {
      c == '9'
    }
    fn test(input: &str) -> IResult<&str, &str> {
      take_while_s!(input, while_s)
    }
    match test(INPUT) {
      Ok((extra, output)) => {
        assert!(
          extra == LEFTOVER,
          "Parser `take_while_s` consumed leftover input."
        );
        assert!(
          output == CONSUMED,
          "Parser `take_while_s` doesn't return the string it consumed on success. \
           Expected `{}`, got `{}`.",
          CONSUMED,
          output
        );
      }
      other => panic!(
        "Parser `take_while_s` didn't succeed when it should have. \
         Got `{:?}`.",
        other
      ),
    };
  }

  #[test]
  fn is_not_s_succeed() {
    const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
    const AVOID: &str = "£úçƙ¥á";
    const CONSUMED: &str = "βèƒôřèÂßÇ";
    const LEFTOVER: &str = "áƒƭèř";
    fn test(input: &str) -> IResult<&str, &str> {
      is_not_s!(input, AVOID)
    }
    match test(INPUT) {
      Ok((extra, output)) => {
        assert!(
          extra == LEFTOVER,
          "Parser `is_not_s` consumed leftover input. Leftover `{}`.",
          extra
        );
        assert!(
          output == CONSUMED,
          "Parser `is_not_s` doens't return the string it consumed on success. Expected `{}`, got `{}`.",
          CONSUMED,
          output
        );
      }
      other => panic!(
        "Parser `is_not_s` didn't succeed when it should have. \
         Got `{:?}`.",
        other
      ),
    };
  }

  #[test]
  fn take_until_and_consume_s_succeed() {
    const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
    const FIND: &str = "ÂßÇ";
    const OUTPUT: &str = "βèƒôřè";
    const LEFTOVER: &str = "áƒƭèř";

    match take_until_and_consume_s!(INPUT, FIND) {
      Ok((extra, output)) => {
        assert!(
          extra == LEFTOVER,
          "Parser `take_until_and_consume_s`\
           consumed leftover input. Leftover `{}`.",
          extra
        );
        assert!(
          output == OUTPUT,
          "Parser `take_until_and_consume_s`\
           doens't return the string it selected on success. Expected `{}`, got `{}`.",
          OUTPUT,
          output
        );
      }
      other => panic!(
        "Parser `take_until_and_consume_s` didn't succeed when it should have. \
         Got `{:?}`.",
        other
      ),
    };
  }

  #[test]
  fn take_while_s_succeed_some() {
    const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
    const CONSUMED: &str = "βèƒôřèÂßÇ";
    const LEFTOVER: &str = "áƒƭèř";
    fn while_s(c: char) -> bool {
      c == 'β' || c == 'è' || c == 'ƒ' || c == 'ô' || c == 'ř' || c == 'è' || c == 'Â' || c == 'ß' || c == 'Ç'
    }
    fn test(input: &str) -> IResult<&str, &str> {
      take_while_s!(input, while_s)
    }
    match test(INPUT) {
      Ok((extra, output)) => {
        assert!(
          extra == LEFTOVER,
          "Parser `take_while_s` consumed leftover input."
        );
        assert!(
          output == CONSUMED,
          "Parser `take_while_s` doesn't return the string it consumed on success. \
           Expected `{}`, got `{}`.",
          CONSUMED,
          output
        );
      }
      other => panic!(
        "Parser `take_while_s` didn't succeed when it should have. \
         Got `{:?}`.",
        other
      ),
    };
  }

  #[test]
  fn is_not_s_fail() {
    const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
    const AVOID: &str = "βúçƙ¥";
    fn test(input: &str) -> IResult<&str, &str> {
      is_not_s!(input, AVOID)
    }
    match test(INPUT) {
      Err(Err::Error(_)) => (),
      other => panic!(
        "Parser `is_not_s` didn't fail when it should have. Got `{:?}`.",
        other
      ),
    };
  }

  #[test]
  fn take_while1_s_succeed() {
    const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
    const CONSUMED: &str = "βèƒôřèÂßÇ";
    const LEFTOVER: &str = "áƒƭèř";
    fn while1_s(c: char) -> bool {
      c == 'β' || c == 'è' || c == 'ƒ' || c == 'ô' || c == 'ř' || c == 'è' || c == 'Â' || c == 'ß' || c == 'Ç'
    }
    fn test(input: &str) -> IResult<&str, &str> {
      take_while1_s!(input, while1_s)
    }
    match test(INPUT) {
      Ok((extra, output)) => {
        assert!(
          extra == LEFTOVER,
          "Parser `take_while1_s` consumed leftover input."
        );
        assert!(
          output == CONSUMED,
          "Parser `take_while1_s` doesn't return the string it consumed on success. \
           Expected `{}`, got `{}`.",
          CONSUMED,
          output
        );
      }
      other => panic!(
        "Parser `take_while1_s` didn't succeed when it should have. \
         Got `{:?}`.",
        other
      ),
    };
  }

  #[test]
  fn take_until_and_consume_s_incomplete() {
    const INPUT: &str = "βèƒôřè";
    const FIND: &str = "βèƒôřèÂßÇ";

    match take_until_and_consume_s!(INPUT, FIND) {
      Err(Err::Incomplete(_)) => (),
      other => panic!(
        "Parser `take_until_and_consume_s` didn't require more input when it should have. \
         Got `{:?}`.",
        other
      ),
    };
  }

  #[test]
  fn take_until_s_incomplete() {
    const INPUT: &str = "βèƒôřè";
    const FIND: &str = "βèƒôřèÂßÇ";

    match take_until_s!(INPUT, FIND) {
      Err(Err::Incomplete(_)) => (),
      other => panic!(
        "Parser `take_until_s` didn't require more input when it should have. \
         Got `{:?}`.",
        other
      ),
    };
  }

  #[test]
  fn is_a_s_succeed() {
    const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
    const MATCH: &str = "βèƒôřèÂßÇ";
    const CONSUMED: &str = "βèƒôřèÂßÇ";
    const LEFTOVER: &str = "áƒƭèř";
    fn test(input: &str) -> IResult<&str, &str> {
      is_a_s!(input, MATCH)
    }
    match test(INPUT) {
      Ok((extra, output)) => {
        assert!(
          extra == LEFTOVER,
          "Parser `is_a_s` consumed leftover input. Leftover `{}`.",
          extra
        );
        assert!(
          output == CONSUMED,
          "Parser `is_a_s` doens't return the string it consumed on success. Expected `{}`, got `{}`.",
          CONSUMED,
          output
        );
      }
      other => panic!(
        "Parser `is_a_s` didn't succeed when it should have. \
         Got `{:?}`.",
        other
      ),
    };
  }

  #[test]
  fn take_while1_s_fail() {
    const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
    fn while1_s(c: char) -> bool {
      c == '9'
    }
    fn test(input: &str) -> IResult<&str, &str> {
      take_while1_s!(input, while1_s)
    }
    match test(INPUT) {
      Err(Err::Error(_)) => (),
      other => panic!(
        "Parser `take_while1_s` didn't fail when it should have. \
         Got `{:?}`.",
        other
      ),
    };
  }

  #[test]
  fn is_a_s_fail() {
    const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
    const MATCH: &str = "Ûñℓúçƙ¥";
    fn test(input: &str) -> IResult<&str, &str> {
      is_a_s!(input, MATCH)
    }
    match test(INPUT) {
      Err(Err::Error(_)) => (),
      other => panic!(
        "Parser `is_a_s` didn't fail when it should have. Got `{:?}`.",
        other
      ),
    };
  }

  #[test]
  fn take_until_and_consume_s_error() {
    const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
    const FIND: &str = "Ráñδô₥";

    match take_until_and_consume_s!(INPUT, FIND) {
      Err(Err::Incomplete(_)) => (),
      other => panic!(
        "Parser `take_until_and_consume_s` didn't fail when it should have. \
         Got `{:?}`.",
        other
      ),
    };
  }

  #[test]
  fn take_until_s_error() {
    const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
    const FIND: &str = "Ráñδô₥";

    match take_until_s!(INPUT, FIND) {
      Err(Err::Incomplete(_)) => (),
      other => panic!(
        "Parser `take_until_and_consume_s` didn't fail when it should have. \
         Got `{:?}`.",
        other
      ),
    };
  }

  #[test]
  #[cfg(feature = "alloc")]
  fn recognize_is_a_s() {
    let a = "aabbab";
    let b = "ababcd";

    named!(f <&str,&str>, recognize!(many1!(complete!(alt!( tag_s!("a") | tag_s!("b") )))));

    assert_eq!(f(&a[..]), Ok((&a[6..], &a[..])));
    assert_eq!(f(&b[..]), Ok((&b[4..], &b[..4])));
  }

  #[test]
  fn utf8_indexing() {
    named!(dot(&str) -> &str,
        tag_s!(".")
      );

    let _ = dot("點");
  }

  #[cfg(feature = "alloc")]
  #[test]
  fn case_insensitive() {
    named!(test<&str,&str>, tag_no_case!("ABcd"));
    assert_eq!(test("aBCdefgh"), Ok(("efgh", "aBCd")));
    assert_eq!(test("abcdefgh"), Ok(("efgh", "abcd")));
    assert_eq!(test("ABCDefgh"), Ok(("efgh", "ABCD")));

    named!(test2<&str,&str>, tag_no_case!("ABcd"));
    assert_eq!(test2("aBCdefgh"), Ok(("efgh", "aBCd")));
    assert_eq!(test2("abcdefgh"), Ok(("efgh", "abcd")));
    assert_eq!(test2("ABCDefgh"), Ok(("efgh", "ABCD")));
  }
}
