peg::parser! {
grammar rules() for str {
pub(crate) rule whitespace() = [' ' | '\t']
pub(crate) rule newline() = "\r\n" / "\n" / "\r"
pub(crate) rule number() -> u32
= n:$(['0'..='9']+) {?
n.parse().or(Err("number in u32"))
}
pub(crate) rule int() -> i32
= n:$(['+' | '-']? ['0'..='9']+) {?
n.parse().or(Err("signed number"))
}
pub(crate) rule two_number() -> u8
= n:$(['0'..='9']['0'..='9']) {?
n.parse().or(Err("two-digit number"))
}
pub(crate) rule three_number() -> u16
= n:$(['0'..='9']['0'..='9']['0'..='9']) {?
n.parse().or(Err("three-digit number"))
}
pub(crate) rule float() -> f32
= n:$(['0'..='9']+ "." ['0'..='9']+) {?
n.parse().or(Err("Invalid float"))
}
pub(crate) rule percentage_int() -> u32
= n:number() "%" {?
if n <= 100 {
Ok(n)
} else {
Err("Number out of range")
}
}
pub(crate) rule percentage_float() -> f32
= f:float() "%" {?
if f >= 0.0 && f <= 100.0 {
Ok(f)
} else {
Err("Number out of range")
}
}
pub(crate) rule percentage() -> f32
= p:percentage_int() { p as f32 }
/ p:percentage_float() { p }
pub(crate) rule anchor() -> (f32, f32)
= x:percentage() "," y:percentage()
{
(x, y)
}
pub(crate) rule sequence() -> String
= t:$((!(whitespace() / newline()) [_])+)
{
t.to_string()
}
pub(crate) rule text_block() -> String
= !newline() lines:$((!newline() [_])+ newline()) ++ ()
{
lines.join("").to_string()
}
pub(crate) rule line() -> String
= !(whitespace() / newline()) t:$((!newline() [_])+) newline()
{
t.to_string().trim().to_string()
}
pub(crate) rule multiline() -> Vec<String>
= !(whitespace() / newline()) lines:$(!(whitespace()+ newline()) (!newline() [_])+ newline()) ++ ()
{
lines
.iter()
.map(|l| l.to_string().trim().to_string())
.collect()
}
}
}
#[cfg(test)]
mod test {
#[test]
fn whitespace() {
assert!(super::rules::whitespace(" ").is_ok());
assert!(super::rules::whitespace("\t").is_ok());
assert!(super::rules::whitespace("a").is_err());
}
#[test]
fn newline() {
assert!(super::rules::newline("\n").is_ok());
assert!(super::rules::newline("\r").is_ok());
assert!(super::rules::newline("\r\n").is_ok());
assert!(super::rules::newline("").is_err());
assert!(super::rules::newline("\n\r").is_err());
assert!(super::rules::newline("\n\n").is_err());
assert!(super::rules::newline("a").is_err());
}
#[test]
fn number() {
assert_eq!(super::rules::number("0").unwrap(), 0);
assert_eq!(super::rules::number("1").unwrap(), 1);
assert_eq!(super::rules::number("9").unwrap(), 9);
assert_eq!(super::rules::number("10").unwrap(), 10);
assert_eq!(
super::rules::number("123").unwrap(),
123
);
assert!(super::rules::number("a").is_err());
assert!(super::rules::number(" ").is_err());
}
#[test]
fn signed_number() {
assert_eq!(super::rules::int("0").unwrap(), 0);
assert_eq!(super::rules::int("1").unwrap(), 1);
assert_eq!(super::rules::int("9").unwrap(), 9);
assert_eq!(super::rules::int("10").unwrap(), 10);
assert_eq!(super::rules::int("123").unwrap(), 123);
assert_eq!(super::rules::int("+0").unwrap(), 0);
assert_eq!(super::rules::int("+1").unwrap(), 1);
assert_eq!(super::rules::int("+9").unwrap(), 9);
assert_eq!(super::rules::int("+10").unwrap(), 10);
assert_eq!(super::rules::int("+123").unwrap(), 123);
assert_eq!(super::rules::int("-0").unwrap(), 0);
assert_eq!(super::rules::int("-1").unwrap(), -1);
assert_eq!(super::rules::int("-9").unwrap(), -9);
assert_eq!(super::rules::int("-10").unwrap(), -10);
assert_eq!(super::rules::int("-123").unwrap(), -123);
assert!(super::rules::int("a").is_err());
assert!(super::rules::int(" ").is_err());
}
#[test]
fn two_number() {
assert_eq!(
super::rules::two_number("00").unwrap(),
0
);
assert_eq!(
super::rules::two_number("01").unwrap(),
1
);
assert_eq!(
super::rules::two_number("09").unwrap(),
9
);
assert_eq!(
super::rules::two_number("10").unwrap(),
10
);
assert_eq!(
super::rules::two_number("99").unwrap(),
99
);
assert!(super::rules::two_number("0").is_err());
assert!(super::rules::two_number("000").is_err());
assert!(super::rules::two_number("a").is_err());
assert!(super::rules::two_number(" ").is_err());
}
#[test]
fn three_number() {
assert_eq!(
super::rules::three_number("000").unwrap(),
0
);
assert_eq!(
super::rules::three_number("001").unwrap(),
1
);
assert_eq!(
super::rules::three_number("009").unwrap(),
9
);
assert_eq!(
super::rules::three_number("010").unwrap(),
10
);
assert_eq!(
super::rules::three_number("099").unwrap(),
99
);
assert_eq!(
super::rules::three_number("100").unwrap(),
100
);
assert_eq!(
super::rules::three_number("999").unwrap(),
999
);
assert!(super::rules::three_number("00").is_err());
assert!(super::rules::three_number("0000").is_err());
assert!(super::rules::three_number("a").is_err());
assert!(super::rules::three_number(" ").is_err());
}
#[test]
fn float() {
assert_eq!(super::rules::float("0.0").unwrap(), 0.0);
assert_eq!(super::rules::float("1.0").unwrap(), 1.0);
assert_eq!(super::rules::float("9.0").unwrap(), 9.0);
assert_eq!(
super::rules::float("10.01").unwrap(),
10.01
);
assert_eq!(
super::rules::float("99.0").unwrap(),
99.0
);
assert!(super::rules::float("0").is_err());
assert!(super::rules::float("1").is_err());
assert!(super::rules::float("10").is_err());
assert!(super::rules::float("a").is_err());
assert!(super::rules::float(" ").is_err());
}
#[test]
fn percentage_int() {
assert_eq!(
super::rules::percentage_int("0%").unwrap(),
0
);
assert_eq!(
super::rules::percentage_int("1%").unwrap(),
1
);
assert_eq!(
super::rules::percentage_int("9%").unwrap(),
9
);
assert_eq!(
super::rules::percentage_int("10%").unwrap(),
10
);
assert_eq!(
super::rules::percentage_int("99%").unwrap(),
99
);
assert_eq!(
super::rules::percentage_int("100%").unwrap(),
100
);
assert_eq!(
super::rules::percentage_int("000%").unwrap(),
0
);
assert!(super::rules::percentage_int("10.0%").is_err());
assert!(super::rules::percentage_int("100.1%").is_err());
assert!(super::rules::percentage_int("100.9%").is_err());
assert!(super::rules::percentage_int("101%").is_err());
assert!(super::rules::percentage_int("999%").is_err());
assert!(super::rules::percentage_int("0").is_err());
assert!(super::rules::percentage_int("a").is_err());
assert!(super::rules::percentage_int(" ").is_err());
}
#[test]
fn percentage_float() {
assert_eq!(
super::rules::percentage_float("0.0%").unwrap(),
0.0
);
assert_eq!(
super::rules::percentage_float("1.0%").unwrap(),
1.0
);
assert_eq!(
super::rules::percentage_float("9.0%").unwrap(),
9.0
);
assert_eq!(
super::rules::percentage_float("10.0%").unwrap(),
10.0
);
assert_eq!(
super::rules::percentage_float("99.0%").unwrap(),
99.0
);
assert_eq!(
super::rules::percentage_float("100.0%").unwrap(),
100.0
);
assert_eq!(
super::rules::percentage_float("99.9%").unwrap(),
99.9
);
assert_eq!(
super::rules::percentage_float("0.1%").unwrap(),
0.1
);
assert_eq!(
super::rules::percentage_float("0.9%").unwrap(),
0.9
);
assert!(super::rules::percentage_float("100.1%").is_err());
assert!(super::rules::percentage_float("100.9%").is_err());
assert!(super::rules::percentage_float("100").is_err());
assert!(super::rules::percentage_float("0").is_err());
assert!(super::rules::percentage_float("a").is_err());
assert!(super::rules::percentage_float(" ").is_err());
}
#[test]
fn percentage() {
assert_eq!(
super::rules::percentage("0%").unwrap(),
0.0
);
assert_eq!(
super::rules::percentage("1%").unwrap(),
1.0
);
assert_eq!(
super::rules::percentage("9%").unwrap(),
9.0
);
assert_eq!(
super::rules::percentage("10%").unwrap(),
10.0
);
assert_eq!(
super::rules::percentage("99%").unwrap(),
99.0
);
assert_eq!(
super::rules::percentage("100%").unwrap(),
100.0
);
assert_eq!(
super::rules::percentage("100.0%").unwrap(),
100.0
);
assert_eq!(
super::rules::percentage("000%").unwrap(),
0.0
);
assert!(super::rules::percentage("100.1%").is_err());
assert!(super::rules::percentage("100.9%").is_err());
assert!(super::rules::percentage("101%").is_err());
assert!(super::rules::percentage("999%").is_err());
assert!(super::rules::percentage("0").is_err());
assert!(super::rules::percentage("a").is_err());
assert!(super::rules::percentage(" ").is_err());
}
#[test]
fn anchor() {
assert_eq!(
super::rules::anchor("0%,0%").unwrap(),
(0.0, 0.0)
);
assert_eq!(
super::rules::anchor("1%,1%").unwrap(),
(1.0, 1.0)
);
assert_eq!(
super::rules::anchor("9%,9%").unwrap(),
(9.0, 9.0)
);
assert_eq!(
super::rules::anchor("10%,10%").unwrap(),
(10.0, 10.0)
);
assert_eq!(
super::rules::anchor("99%,99%").unwrap(),
(99.0, 99.0)
);
assert_eq!(
super::rules::anchor("100%,100%").unwrap(),
(100.0, 100.0)
);
assert_eq!(
super::rules::anchor("100.0%,100.0%").unwrap(),
(100.0, 100.0)
);
assert_eq!(
super::rules::anchor("000%,000%").unwrap(),
(0.0, 0.0)
);
assert!(super::rules::anchor("100.1%,100.1%").is_err());
assert!(super::rules::anchor("100.9%,100.9%").is_err());
assert!(super::rules::anchor("101%,101%").is_err());
assert!(super::rules::anchor("999%,999%").is_err());
assert!(super::rules::anchor("0,0").is_err());
assert!(super::rules::anchor("a").is_err());
assert!(super::rules::anchor(" ").is_err());
}
#[test]
fn sequence() {
assert_eq!(
super::rules::sequence("Hello,world!").unwrap(),
"Hello,world!".to_string()
);
assert!(super::rules::sequence(" Hello,world!").is_err());
assert!(super::rules::sequence("Hello, world!").is_err());
assert!(super::rules::sequence("Hello,world! ").is_err());
assert!(super::rules::sequence("\nHello,world!").is_err());
assert!(super::rules::sequence("Hello,\nworld!").is_err());
assert!(super::rules::sequence("Hello,world!\n").is_err());
assert!(super::rules::sequence(" Hello,world! \n").is_err());
}
#[test]
fn text_block() {
assert_eq!(
super::rules::text_block("Hello, world!\n").unwrap(),
"Hello, world!\n".to_string()
);
assert_eq!(
super::rules::text_block("Hello, world!\nThis is a test.\n")
.unwrap(),
"Hello, world!\nThis is a test.\n".to_string()
);
assert_eq!(
super::rules::text_block(
"Hello, world!\nThis is a test.\nHow are you?\n"
)
.unwrap(),
"Hello, world!\nThis is a test.\nHow are you?\n".to_string()
);
assert!(super::rules::text_block("").is_err());
assert!(super::rules::text_block("Hello, world!").is_err());
assert!(super::rules::text_block("\nHello, world!\n").is_err());
assert!(
super::rules::text_block("Hello, world!\nThis is a test.\n\n")
.is_err()
);
assert!(super::rules::text_block("some\ntext\n\nover\nline").is_err());
}
#[test]
fn line() {
assert_eq!(
super::rules::line("Hello, world!\n").unwrap(),
"Hello, world!".to_string()
);
assert_eq!(
super::rules::line("Hello, world! \n").unwrap(),
"Hello, world!".to_string()
);
assert!(super::rules::line(" Hello, world!\n").is_err());
assert!(super::rules::line("Hello, world!").is_err());
assert!(super::rules::line("\nHello, world!").is_err());
assert!(super::rules::line("Hello, world!\nThis is a test.").is_err());
}
#[test]
fn multiline() {
assert_eq!(
super::rules::multiline("Hello, world!\n").unwrap(),
vec!["Hello, world!".to_string()]
);
assert_eq!(
super::rules::multiline("Hello, world!\nThis is a test.\n")
.unwrap(),
vec![
"Hello, world!".to_string(),
"This is a test.".to_string(),
]
);
assert_eq!(
super::rules::multiline(
"Hello, world!\nThis is a test.\nHow are you?\n"
)
.unwrap(),
vec![
"Hello, world!".to_string(),
"This is a test.".to_string(),
"How are you?".to_string(),
]
);
assert!(super::rules::multiline("").is_err());
assert!(super::rules::multiline("Hello, world!").is_err());
assert!(super::rules::multiline(" Hello, world!\n").is_err());
assert!(super::rules::multiline("\nHello, world!\n").is_err());
assert!(
super::rules::multiline("Hello, world!\nThis is a test.\n\n")
.is_err()
);
assert!(
super::rules::multiline("Hello, world!\nThis is a test.\n \n")
.is_err()
);
assert!(super::rules::multiline("some\ntext\n\nover\nline").is_err());
}
}