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 lines::Lines;
use memchr::memchr2;
#[cfg_attr(test, derive(PartialEq))]
#[derive(Debug)]
@ -7,12 +8,14 @@ pub struct Block;
impl Block {
// return (name, args, contents-begin, contents-end, end)
pub fn parse(src: &str) -> Option<(&str, Option<&str>, usize, usize, usize)> {
if src.len() < 17 || !src[0..8].eq_ignore_ascii_case("#+BEGIN_") {
debug_assert!(src.starts_with("#+"));
if !src[2..8].eq_ignore_ascii_case("BEGIN_") {
return None;
}
let name = until_while!(src, 8, |c| c == b' ' || c == b'\n', |c: u8| c
.is_ascii_alphabetic())?;
let name = memchr2(b' ', b'\n', src.as_bytes())
.filter(|&i| src.as_bytes()[8..i].iter().all(|c| c.is_ascii_alphabetic()))?;
let mut lines = Lines::new(src);
let (pre_cont_end, cont_beg, _) = lines.next()?;
let args = if pre_cont_end == name {

View file

@ -1,3 +1,6 @@
use lines::Lines;
use memchr::memchr2;
#[cfg_attr(test, derive(PartialEq))]
#[derive(Debug)]
pub struct DynBlock;
@ -5,17 +8,26 @@ pub struct DynBlock;
impl DynBlock {
// return (name, parameters, contents-begin, contents-end, end)
pub fn parse(src: &str) -> Option<(&str, Option<&str>, usize, usize, usize)> {
if src.len() < 17 || !src[0..9].eq_ignore_ascii_case("#+BEGIN: ") {
debug_assert!(src.starts_with("#+"));
if !src[2..9].eq_ignore_ascii_case("BEGIN: ") {
return None;
}
let bytes = src.as_bytes();
let args = eol!(src);
let name = until_while!(src, 9, |c| c == b' ' || c == b'\n', |c: u8| c
.is_ascii_alphabetic())?;
let name = memchr2(b' ', b'\n', &bytes[9..])
.map(|i| i + 9)
.filter(|&i| {
src.as_bytes()[9..i]
.iter()
.all(|&c| c.is_ascii_alphabetic())
})?;
let mut lines = Lines::new(src);
let (mut pre_cont_end, _, _) = lines.next()?;
let mut pos = 0;
for line_end in lines!(src) {
if src[pos..line_end].trim().eq_ignore_ascii_case("#+END:") {
while let Some((cont_end, end, line)) = lines.next() {
if line.trim().eq_ignore_ascii_case("#+END:") {
return Some((
&src[8..name].trim(),
if name == args {
@ -24,11 +36,11 @@ impl DynBlock {
Some(&src[name..args].trim())
},
args,
pos,
line_end,
pre_cont_end,
end,
));
}
pos = line_end;
pre_cont_end = cont_end;
}
None
@ -45,6 +57,6 @@ CONTENTS
#+END:
"
),
Some(("clocktable", Some(":scope file"), 31, 41, 48))
Some(("clocktable", Some(":scope file"), 31, 40, 48))
)
}

View file

@ -1,23 +1,19 @@
use memchr::memchr;
#[cfg_attr(test, derive(PartialEq))]
#[derive(Debug)]
pub struct FnDef;
#[inline]
fn valid_label(ch: u8) -> bool {
ch.is_ascii_alphanumeric() || ch == b'-' || ch == b'_'
}
impl FnDef {
pub fn parse(src: &str) -> Option<(&str, &str, usize)> {
if cfg!(test) {
starts_with!(src, "[fn:");
}
debug_assert!(src.starts_with("[fn:"));
let label = until_while!(src, 4, b']', valid_label)?;
if label == 4 {
return None;
}
let label = memchr(b']', src.as_bytes()).filter(|&i| {
i != 4
&& src.as_bytes()[4..i]
.iter()
.all(|&c| c.is_ascii_alphanumeric() || c == b'-' || c == b'_')
})?;
let end = eol!(src);

View file

@ -1,3 +1,5 @@
use memchr::{memchr, memchr2};
pub struct Keyword;
#[cfg_attr(test, derive(PartialEq))]
@ -25,16 +27,18 @@ pub enum Key<'a> {
impl Keyword {
// return (key, value, offset)
pub fn parse(src: &str) -> Option<(Key<'_>, &str, usize)> {
if cfg!(test) {
starts_with!(src, "#+");
}
debug_assert!(src.starts_with("#+"));
let key_end = until_while!(src, 2, |c| c == b':' || c == b'[', |c: u8| c
.is_ascii_alphabetic()
|| c == b'_')?;
let bytes = src.as_bytes();
let key_end = memchr2(b':', b'[', bytes).filter(|&i| {
bytes[2..i]
.iter()
.all(|&c| c.is_ascii_alphabetic() || c == b'_')
})?;
let option = if src.as_bytes()[key_end] == b'[' {
let option = until_while!(src, key_end, b']', |c: u8| c != b'\n')?;
let option = if bytes[key_end] == b'[' {
let option =
memchr(b']', bytes).filter(|&i| bytes[key_end..i].iter().all(|&c| c != b'\n'))?;
expect!(src, option + 1, b':')?;
option + 1
} else {
@ -100,8 +104,6 @@ fn parse() {
);
assert!(Keyword::parse("#+KE Y: VALUE").is_none());
assert!(Keyword::parse("#+ KEY: VALUE").is_none());
assert!(Keyword::parse("# +KEY: VALUE").is_none());
assert!(Keyword::parse(" #+KEY: VALUE").is_none());
assert_eq!(
Keyword::parse("#+RESULTS:"),

View file

@ -15,7 +15,7 @@ impl List {
let i = bytes
.iter()
.position(|&c| !c.is_ascii_digit())
.unwrap_or_else(|| src.len());
.unwrap_or_else(|| src.len() - 1);
let c = bytes[i];
if !(c == b'.' || c == b')') {
return (false, false);