refactor: cleanup utils macros

This commit is contained in:
PoiScript 2019-02-07 15:54:16 +08:00
parent 346ebc83d7
commit 0b355b498c
18 changed files with 285 additions and 297 deletions

View file

@ -1,4 +1,5 @@
use jetscii::Substring;
use memchr::memchr2;
#[cfg_attr(test, derive(PartialEq))]
#[derive(Debug)]
@ -7,54 +8,83 @@ pub struct Macros<'a> {
pub args: Option<&'a str>,
}
fn valid_name(ch: u8) -> bool {
ch.is_ascii_alphanumeric() || ch == b'-' || ch == b'_'
}
impl<'a> Macros<'a> {
pub fn parse(src: &'a str) -> Option<(Macros<'a>, usize)> {
starts_with!(src, "{{{");
debug_assert!(src.starts_with("{{{"));
expect!(src, 3, |c: u8| c.is_ascii_alphabetic())?;
let name = until_while!(src, 3, |c| c == b'}' || c == b'(', valid_name)?;
let bytes = src.as_bytes();
let name = memchr2(b'}', b'(', bytes).filter(|&i| {
bytes[3..i]
.iter()
.all(|&c| c.is_ascii_alphanumeric() || c == b'-' || c == b'_')
})?;
if src.as_bytes()[name] == b'}' {
Some(if bytes[name] == b'}' {
expect!(src, name + 1, b'}')?;
expect!(src, name + 2, b'}')?;
Some((
(
Macros {
name: &src[3..name],
args: None,
},
name + 3,
))
)
} else {
let end = Substring::new("}}}").find(&src[name..]).map(|i| i + name)?;
expect!(src, end - 1, b')')?;
Some((
let end = Substring::new(")}}}")
.find(&src[name..])
.map(|i| i + name)?;
(
Macros {
name: &src[3..name],
args: if name == end {
None
} else {
Some(&src[name + 1..end - 1])
Some(&src[name + 1..end])
},
},
end + 3,
))
}
end + 4,
)
})
}
}
#[test]
fn parse() {
parse_succ!(Macros, "{{{poem(red,blue)}}}", name: "poem", args: Some("red,blue"));
parse_succ!(Macros, "{{{poem())}}}", name: "poem", args: Some(")"));
parse_succ!(Macros, "{{{author}}}", name: "author", args: None);
parse_fail!(Macros, "{{author}}}");
parse_fail!(Macros, "{{{0uthor}}}");
parse_fail!(Macros, "{{{author}}");
parse_fail!(Macros, "{{{poem(}}}");
parse_fail!(Macros, "{{{poem)}}}");
assert_eq!(
Macros::parse("{{{poem(red,blue)}}}"),
Some((
Macros {
name: "poem",
args: Some("red,blue")
},
"{{{poem(red,blue)}}}".len()
))
);
assert_eq!(
Macros::parse("{{{poem())}}}"),
Some((
Macros {
name: "poem",
args: Some(")")
},
"{{{poem())}}}".len()
))
);
assert_eq!(
Macros::parse("{{{author}}}"),
Some((
Macros {
name: "author",
args: None
},
"{{{author}}}".len()
))
);
assert_eq!(Macros::parse("{{{0uthor}}}"), None);
assert_eq!(Macros::parse("{{{author}}"), None);
assert_eq!(Macros::parse("{{{poem(}}}"), None);
assert_eq!(Macros::parse("{{{poem)}}}"), None);
}