refactor(parser): wrap some objects and elements with struct
This commit is contained in:
parent
69534576f1
commit
56e289fb48
22 changed files with 1055 additions and 875 deletions
|
|
@ -1,60 +1,80 @@
|
|||
use jetscii::Substring;
|
||||
use memchr::memchr2;
|
||||
|
||||
/// returns (macros name, macros arguments, offset)
|
||||
#[inline]
|
||||
pub fn parse(text: &str) -> Option<(&str, Option<&str>, usize)> {
|
||||
debug_assert!(text.starts_with("{{{"));
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[derive(Debug)]
|
||||
pub struct Macros<'a> {
|
||||
pub name: &'a str,
|
||||
pub arguments: Option<&'a str>,
|
||||
}
|
||||
|
||||
let bytes = text.as_bytes();
|
||||
if text.len() <= 3 || !bytes[3].is_ascii_alphabetic() {
|
||||
return None;
|
||||
}
|
||||
impl<'a> Macros<'a> {
|
||||
#[inline]
|
||||
pub fn parse(text: &str) -> Option<(Macros<'_>, usize)> {
|
||||
debug_assert!(text.starts_with("{{{"));
|
||||
|
||||
let (name, off) = memchr2(b'}', b'(', bytes)
|
||||
.filter(|&i| {
|
||||
bytes[3..i]
|
||||
.iter()
|
||||
.all(|&c| c.is_ascii_alphanumeric() || c == b'-' || c == b'_')
|
||||
})
|
||||
.map(|i| (&text[3..i], i))?;
|
||||
|
||||
let (args, off) = if bytes[off] == b'}' {
|
||||
if text.len() <= off + 2 || bytes[off + 1] != b'}' || bytes[off + 2] != b'}' {
|
||||
let bytes = text.as_bytes();
|
||||
if text.len() <= 3 || !bytes[3].is_ascii_alphabetic() {
|
||||
return None;
|
||||
}
|
||||
(None, off + 3 /* }}} */)
|
||||
} else {
|
||||
Substring::new(")}}}")
|
||||
.find(&text[off..])
|
||||
.map(|i| (Some(&text[off + 1..off + i]), off + i + 4 /* )}}} */))?
|
||||
};
|
||||
|
||||
Some((name, args, off))
|
||||
}
|
||||
let (name, off) = memchr2(b'}', b'(', bytes)
|
||||
.filter(|&i| {
|
||||
bytes[3..i]
|
||||
.iter()
|
||||
.all(|&c| c.is_ascii_alphanumeric() || c == b'-' || c == b'_')
|
||||
})
|
||||
.map(|i| (&text[3..i], i))?;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn parse() {
|
||||
use super::parse;
|
||||
let (arguments, off) = if bytes[off] == b'}' {
|
||||
if text.len() <= off + 2 || bytes[off + 1] != b'}' || bytes[off + 2] != b'}' {
|
||||
return None;
|
||||
}
|
||||
(None, off + "}}}".len())
|
||||
} else {
|
||||
Substring::new(")}}}")
|
||||
.find(&text[off..])
|
||||
.map(|i| (Some(&text[off + 1..off + i]), off + i + ")}}}".len()))?
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
parse("{{{poem(red,blue)}}}"),
|
||||
Some(("poem", Some("red,blue"), "{{{poem(red,blue)}}}".len()))
|
||||
);
|
||||
assert_eq!(
|
||||
parse("{{{poem())}}}"),
|
||||
Some(("poem", Some(")"), "{{{poem())}}}".len()))
|
||||
);
|
||||
assert_eq!(
|
||||
parse("{{{author}}}"),
|
||||
Some(("author", None, "{{{author}}}".len()))
|
||||
);
|
||||
|
||||
assert_eq!(parse("{{{0uthor}}}"), None);
|
||||
assert_eq!(parse("{{{author}}"), None);
|
||||
assert_eq!(parse("{{{poem(}}}"), None);
|
||||
assert_eq!(parse("{{{poem)}}}"), None);
|
||||
Some((Macros { name, arguments }, off))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse() {
|
||||
assert_eq!(
|
||||
Macros::parse("{{{poem(red,blue)}}}"),
|
||||
Some((
|
||||
Macros {
|
||||
name: "poem",
|
||||
arguments: Some("red,blue")
|
||||
},
|
||||
"{{{poem(red,blue)}}}".len()
|
||||
))
|
||||
);
|
||||
assert_eq!(
|
||||
Macros::parse("{{{poem())}}}"),
|
||||
Some((
|
||||
Macros {
|
||||
name: "poem",
|
||||
arguments: Some(")")
|
||||
},
|
||||
"{{{poem())}}}".len()
|
||||
))
|
||||
);
|
||||
assert_eq!(
|
||||
Macros::parse("{{{author}}}"),
|
||||
Some((
|
||||
Macros {
|
||||
name: "author",
|
||||
arguments: 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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue