scanner/macros: rewrite check! to be simpler to use, add isLineBreak!

This commit is contained in:
Paul Stemmet 2021-06-16 19:16:39 +00:00 committed by Paul Stemmet
parent 3526cd29c4
commit ba10beb0c6
2 changed files with 57 additions and 32 deletions

View file

@ -34,38 +34,62 @@ macro_rules! cow {
/// cased to return an UnexpectedEOF if it encounters an
/// empty slice
macro_rules! check {
($buffer:expr, $(@$pos:expr,)? is $( $byte:pat )|+ $(, else $error:expr)? ) => {
{
let b = match $buffer$([$pos..])? {
[] => Err(false),
$([$byte, ..])|+ => Ok(true),
_ => Ok(false)
(~ $buffer:expr $(, $offset:expr )? => $( $match:tt )|+ $(, else $error:expr)? ) => {
check!(@priv $buffer.as_bytes() $(, $offset )? => $( $match )|+ $(, else $error)?)
};
check!(@priv b $(=> $error)? )
}
};
($buffer:expr, $(@$pos:expr,)? not $( $byte:pat )|+ $(, else $error:expr)? ) => {
{
let b = match $buffer$([$pos..])? {
[] => Err(true),
$([$byte, ..])|+ => Ok(false),
_ => Ok(true)
($buffer:expr $(, $offset:expr )? => $( $match:tt )|+ $(, else $error:expr)? ) => {
check!(@priv $buffer $(, $offset )? => $( $match )|+ $(, else $error)?)
};
check!(@priv b $(=> $error)? )
/* Private variants */
(@priv $buffer:expr, $offset:expr => $( $match:tt )|+) => {
match $buffer.get($offset..) {
Some(buffer) => check!(@priv buffer => $( $match )|+),
None => false
}
};
(@priv $bool:expr) => {
match $bool {
Ok(b) | Err(b) => b
(@priv $buffer:expr => $( $match:tt )|+) => {
match $buffer {
$( check!(@ptn $match) )|+ => true,
_ => false
}
};
(@priv $bool:expr => $error:expr) => {
match $bool {
Ok(true) => Ok(()),
Ok(false) => Err($error),
Err(_) => Err($crate::scanner::error::ScanError::UnexpectedEOF),
(@priv $buffer:expr, $offset:expr => $( $match:tt )|+, else $error:expr) => {
match $buffer.get($offset..) {
Some(buffer) => check!(@priv buffer => $( $match )|+ else $error),
_ => Err($error)
}
};
(@priv $buffer:expr => $( $match:tt )|+, else $error:expr) => {
match $buffer {
$( check!(@ptn $match) )|+ => Ok(()),
[] => Err($crate::scanner::error::ScanError::UnexpectedEOF),
_ => Err($error)
}
};
// Note we use macro path rules to first try matching the given
// token as a literal, e.g a b'_', then try it as a pattern
(@ptn $byte:literal) => {
[$byte, ..]
};
(@ptn $match:pat) => {
$match
};
}
macro_rules! isLineBreak {
(~ $buffer:expr $(, $offset:expr )? ) => {
isLineBreak!($buffer.as_bytes() $(, $offset )? )
};
($buffer:expr $(, $offset:expr )? ) => {
check!($buffer $(, $offset)? =>
b'\r' /* CR #xD */
| b'\n' /* LF #xA */
| [b'\xC2', b'\x85', ..] /* NEL #x85 */
| [b'\xE2', b'\x80', b'\xA8', ..] /* LS #x2028 */
| [b'\xE2', b'\x80', b'\xA9', ..] /* PS #x2029 */
)
};
}

View file

@ -164,7 +164,7 @@ impl<'a> Scanner<'a>
{
let mut buffer = self.buffer;
if check!(buffer.as_bytes(), not b'%')
if !check!(~buffer => b'%')
{
return Ok(None);
}
@ -224,7 +224,7 @@ impl<'a> Scanner<'a>
// %TAG !handle! tag-prefix # a comment \n
// ^
check!(buffer.as_bytes(), is b'!', else ScanError::InvalidTagHandle)?;
check!(~buffer => b'!', else ScanError::InvalidTagHandle)?;
markers += 1;
@ -253,7 +253,7 @@ impl<'a> Scanner<'a>
// Check that there is >= 1 whitespace between handle and
// prefix
check!(buffer.as_bytes(), is b' ', else ScanError::InvalidTagPrefix)?;
check!(~buffer => b' ', else ScanError::InvalidTagPrefix)?;
Self::eat_whitespace(&mut buffer, false);
@ -270,7 +270,7 @@ impl<'a> Scanner<'a>
// %TAG !named! tag-prefix # a comment\n
// ^
// Check there is whitespace or a newline after the tag
check!(buffer.as_bytes(), is b' ' | b'\n', else ScanError::InvalidTagPrefix)?;
check!(~buffer => b' ' | b'\n', else ScanError::InvalidTagPrefix)?;
Token::TagDirective(cow!(handle), cow!(prefix))
},
@ -319,8 +319,9 @@ impl<'a> Scanner<'a>
// There does not necessarily need to be a whitespace so we
// also check against a list of valid starting
// tokens
check!(buffer.as_bytes(),
is b' ' | b'\n' | b'?' | b',' | b']' | b'}' | b'%' | b'@' | b'`',
check!(~buffer
=> b' ' | b'\n' | b'?' | b',' | b']' | b'}' | b'%' | b'@' | b'`',
else ScanError::InvalidAnchorName
)?;