use crate::types::{OKeyPair, OType};
use nom::{
branch::alt,
bytes::complete::{is_not, tag},
character::complete::{digit1, one_of},
combinator::opt,
error::ErrorKind,
multi::{many0, many1},
sequence::delimited,
IResult,
};
use alloc::vec::Vec;
use core::{mem, str};
pub fn get_vec_parser(input: &str) -> IResult<&str, Vec<OKeyPair>> {
many1(build_get_vec_parser)(input)
}
fn build_get_vec_parser(input: &str) -> IResult<&str, OKeyPair> {
let (input, found_keypair) = keypair_parser(input)?; let (input, _) = strip_whitespace(input)?;
Ok((input, found_keypair))
}
fn strip_whitespace(input: &str) -> IResult<&str, ()> {
let (input, _) = many0(tag(" "))(input)?; let (input, _) = opt(tag("\n"))(input)?; let (input, _) = many0(tag(" "))(input)?;
Ok((input, ()))
}
fn keypair_parser(input: &str) -> IResult<&str, OKeyPair> {
let (input, name) = keypair_name_disallow_parser(input)?; let (input, _) = tag(": ")(input)?; let (input, data) = key_parser(input)?; let (input, _) = tag(";")(input)?;
Ok((input, OKeyPair { name, data }))
}
fn keypair_name_disallow_parser(input: &str) -> IResult<&str, OType> {
let (input, name) = key_parser(input)?;
let issued_error = Err(nom::Err::Error((input, ErrorKind::Permutation)));
match name {
OType::ObjectType(_) | OType::ArrayType(_) => issued_error,
_ => Ok((input, name)),
}
}
fn key_parser(input: &str) -> IResult<&str, OType> {
alt((
key_int_parser, key_string_parser, key_object_parser, key_array_parser, ))(input)
}
fn key_array_parser(input: &str) -> IResult<&str, OType> {
let (input, _) = tag("[")(input)?; let (input, found_otype) = build_key_array_parser(input)?; let (input, _) = tag("]")(input)?;
Ok((input, found_otype))
}
fn key_array_parser_cycle(input: &str) -> IResult<&str, OType> {
let (input, _) = strip_whitespace(input)?; let (input, found_otype) = key_parser(input)?; let (input, _) = tag(";")(input)?; let (input, _) = strip_whitespace(input)?;
Ok((input, found_otype))
}
fn build_key_array_parser(input: &str) -> IResult<&str, OType> {
let (input, found_otype) = many0(key_array_parser_cycle)(input)?;
let first_val = match found_otype.first() {
Some(x) => x,
None => return Err(nom::Err::Error((input, ErrorKind::NonEmpty))),
};
for found_value in found_otype.iter() {
if mem::discriminant(first_val) != mem::discriminant(found_value) {
return Err(nom::Err::Error((input, ErrorKind::OneOf)));
}
}
Ok((input, OType::ArrayType(found_otype)))
}
fn key_object_parser(input: &str) -> IResult<&str, OType> {
let (input, _) = tag("{")(input)?; let (input, _) = strip_whitespace(input)?; let (input, found_vec) = get_vec_parser(input)?; let (input, _) = strip_whitespace(input)?; let (input, _) = tag("}")(input)?;
Ok((input, OType::ObjectType(found_vec)))
}
fn key_int_parser(input: &str) -> IResult<&str, OType> {
let (input, found_neg) = opt(tag("-"))(input)?; let (input, found_digits) = digit1(input)?; let (_, found_otype) = build_key_int_parser(found_digits, found_neg.is_some())?;
Ok((input, found_otype))
}
fn build_key_int_parser(input: &str, is_neg_num: bool) -> IResult<&str, OType> {
let mut input_as_int =
str::parse::<i32>(input).map_err(|_| nom::Err::Error((input, ErrorKind::Digit)))?;
if is_neg_num {
input_as_int = -input_as_int;
}
Ok((input, OType::IntType(input_as_int)))
}
fn key_string_parser(input: &str) -> IResult<&str, OType> {
let (input, removed_quotes) = delimited(one_of("\"'"), is_not("\"'"), one_of("\"'"))(input)?;
Ok((input, OType::StringType(removed_quotes)))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn key_array_parser_test() {
assert_eq!(
Ok((
"",
OType::ArrayType(vec![
OType::IntType(53234),
OType::IntType(365),
OType::IntType(-59823)
])
)),
key_array_parser("[ 53234; 365; -59823; ]")
); assert_ne!(
Ok((
"",
OType::ArrayType(vec![
OType::IntType(53234),
OType::StringType("Shouldn't work")
])
)),
key_array_parser("[ 53234; 'Shouldn't work'; ]")
); }
#[test]
fn keypair_name_disallow_parser_test() {
assert_eq!(
Err(nom::Err::Error((": 73892;", ErrorKind::Permutation))),
get_vec_parser("{ 45223: 'adfgoj'; }: 73892;")
); assert_eq!(
Err(nom::Err::Error((": 73892;", ErrorKind::Permutation))),
get_vec_parser("[ 1234; 4632; 2523; ]: 73892;")
) }
#[test]
fn key_object_parser_test() {
let expected_result: Vec<OKeyPair> = vec![
OKeyPair {
name: OType::StringType("Object test"),
data: OType::IntType(672342),
},
OKeyPair {
name: OType::IntType(847624),
data: OType::StringType("Second value}"),
},
];
assert_eq!(
Ok(("", OType::ObjectType(expected_result))),
key_object_parser("{'Object test': 672342; 847624: 'Second value}'; }")
);
}
#[test]
fn keypair_parser_basic_test() {
let expected_keypair = OKeyPair {
name: OType::StringType("Testing keypairs.."),
data: OType::IntType(8678234),
};
assert_eq!(
Ok(("", expected_keypair)),
keypair_parser("'Testing keypairs..': 8678234;")
); }
#[test]
fn key_int_parser_test() {
assert_eq!(Ok(("", OType::IntType(1234))), key_int_parser("1234")); assert_eq!(Ok(("", OType::IntType(6356234))), key_int_parser("6356234")); assert_eq!(Ok(("", OType::IntType(-46234))), key_int_parser("-46234")) }
#[test]
fn key_string_parser_test() {
assert_eq!(
Ok(("", OType::StringType("test"))),
key_string_parser("'test'")
); assert_eq!(
Ok(("", OType::StringType("test"))),
key_string_parser("\"test\"")
); assert_ne!(
Ok(("", OType::StringType("224521"))),
key_string_parser("224521")
); assert_eq!(
Ok(("", OType::StringType("1234"))),
key_string_parser("'1234'")
); }
#[test]
fn get_vec_parser_basic_test() {
let input = "'This is a name': 'And this is data'; 63452123: { 'Inside an object!': 765234; 423457: 6823473; };";
let inside_obj: Vec<OKeyPair> = vec![
OKeyPair {
name: OType::StringType("Inside an object!"),
data: OType::IntType(765234),
},
OKeyPair {
name: OType::IntType(423457),
data: OType::IntType(6823473),
},
];
let expected_result: Vec<OKeyPair> = vec![
OKeyPair {
name: OType::StringType("This is a name"),
data: OType::StringType("And this is data"),
},
OKeyPair {
name: OType::IntType(63452123),
data: OType::ObjectType(inside_obj),
},
];
assert_eq!(Ok(("", expected_result)), get_vec_parser(input));
}
#[test]
fn get_vec_parser_multiline_test() {
let input = "'first line': 324325;\n'second line': 'woo!';";
let expected_result: Vec<OKeyPair> = vec![
OKeyPair {
name: OType::StringType("first line"),
data: OType::IntType(324325),
},
OKeyPair {
name: OType::StringType("second line"),
data: OType::StringType("woo!"),
},
];
assert_eq!(Ok(("", expected_result)), get_vec_parser(input));
}
}