use std::borrow::Borrow;
use std::fmt;
use lalrpop_util::ParseError;
use regex_syntax::hir::{self, Hir};
use crate::Error;
use crate::Result;
use crate::packet::prelude::*;
use crate::types::SignatureType;
pub(crate) mod lexer;
lalrpop_util::lalrpop_mod!(
#[allow(clippy::all)]
#[allow(unused_parens)]
grammar,
"/regex/grammar.rs"
);
pub(crate) use self::lexer::Token;
pub(crate) use self::lexer::{Lexer, LexicalError};
const TRACE: bool = false;
pub(crate) fn parse_error_downcast(e: ParseError<usize, Token, LexicalError>)
-> ParseError<usize, String, LexicalError>
{
match e {
ParseError::UnrecognizedToken {
token: (start, t, end),
expected,
} => ParseError::UnrecognizedToken {
token: (start, t.into(), end),
expected,
},
ParseError::ExtraToken {
token: (start, t, end),
} => ParseError::ExtraToken {
token: (start, t.into(), end),
},
ParseError::InvalidToken { location }
=> ParseError::InvalidToken { location },
ParseError::User { error }
=> ParseError::User { error },
ParseError::UnrecognizedEof { location, expected }
=> ParseError::UnrecognizedEof { location, expected },
}
}
fn generate_class(caret: bool, chars: impl Iterator<Item=char>) -> Hir
{
tracer!(TRACE, "generate_class");
let chars: Vec<Option<char>> = chars
.map(Some)
.chain(std::iter::once(None))
.chain(std::iter::once(None))
.collect();
if chars.len() == 2 {
unreachable!();
} else {
let r = chars
.windows(3)
.scan(0,
|skip: &mut usize, x: &[Option<char>]|
-> Option<Option<hir::ClassUnicodeRange>>
{
if *skip > 0 {
*skip -= 1;
t!("Skipping: {:?} (skip now: {})", x, skip);
Some(None)
} else {
match (x[0], x[1], x[2]) {
(Some(a), Some('-'), Some(c)) => {
*skip = 2;
t!("range for '{}-{}'", a, c);
Some(Some(hir::ClassUnicodeRange::new(a, c)))
}
(Some(a), _, _) => {
t!("range for '{}'", a);
Some(Some(hir::ClassUnicodeRange::new(a, a)))
}
(None, _, _) => unreachable!(),
}
}
})
.flatten();
let mut class = hir::Class::Unicode(hir::ClassUnicode::new(r));
if caret {
class.negate();
}
Hir::class(class)
}
}
#[derive(Clone, Debug)]
pub struct Regex {
re: String,
regex: regex::Regex,
disable_sanitizations: bool,
}
assert_send_and_sync!(Regex);
impl PartialEq for Regex {
fn eq(&self, other: &Self) -> bool {
self.re == other.re
&& self.disable_sanitizations == other.disable_sanitizations
}
}
impl Eq for Regex {}
impl Regex {
pub fn new(re: &str) -> Result<Self>
{
let lexer = Lexer::new(re);
let hir = match grammar::RegexParser::new().parse(re, lexer) {
Ok(hir) => hir,
Err(err) => return Err(parse_error_downcast(err).into()),
};
let regex = regex::RegexBuilder::new(&hir.to_string())
.build()?;
Ok(Self {
re: re.into(),
regex,
disable_sanitizations: false,
})
}
pub fn from_bytes(re: &[u8]) -> Result<Self> {
Self::new(std::str::from_utf8(re)?)
}
pub fn as_str(&self) -> &str {
&self.re
}
pub fn disable_sanitizations(&mut self, disabled: bool) {
self.disable_sanitizations = disabled;
}
pub fn is_match(&self, s: &str) -> bool {
if ! self.disable_sanitizations && s.chars().any(char::is_control) {
return false;
}
self.is_match_clean(s)
}
fn is_match_clean(&self, s: &str) -> bool {
self.regex.is_match(s)
}
pub fn matches_userid(&self, u: &UserID) -> bool {
if let Ok(u) = std::str::from_utf8(u.value()) {
self.is_match(u)
} else {
false
}
}
}
#[derive(Clone, Debug)]
enum RegexSet_ {
Regex(Regex),
Invalid,
Everything,
}
assert_send_and_sync!(RegexSet_);
#[derive(Clone)]
pub struct RegexSet {
re_bytes: Vec<Vec<u8>>,
re_set: RegexSet_,
disable_sanitizations: bool,
}
assert_send_and_sync!(RegexSet);
impl PartialEq for RegexSet {
fn eq(&self, other: &Self) -> bool {
self.re_bytes == other.re_bytes
&& self.disable_sanitizations == other.disable_sanitizations
}
}
impl Eq for RegexSet {}
impl fmt::Debug for RegexSet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_struct("RegexSet");
match self.re_set {
RegexSet_::Everything => {
d.field("regex", &"<Everything>")
}
RegexSet_::Invalid => {
d.field("regex", &"<Invalid>")
}
RegexSet_::Regex(ref r) => {
d.field("regex", &r.regex)
}
}
.field("sanitizations", &!self.disable_sanitizations)
.finish()
}
}
impl RegexSet {
pub fn new<'a, RE, I>(res: I) -> Result<Self>
where RE: Borrow<&'a str>,
I: IntoIterator<Item=RE>,
{
tracer!(TRACE, "RegexSet::new");
let mut regexes = Vec::with_capacity(2);
let mut had_good = false;
let mut had_bad = false;
let mut re_bytes = Vec::new();
for re in res {
let re = re.borrow();
re_bytes.push(re.as_bytes().into());
let lexer = Lexer::new(re);
match grammar::RegexParser::new().parse(re, lexer) {
Ok(hir) => {
had_good = true;
regexes.push(hir);
}
Err(err) => {
had_bad = true;
t!("Compiling {:?}: {}", re, err);
}
}
}
if had_bad && ! had_good {
t!("All regular expressions were invalid.");
Ok(RegexSet {
re_bytes,
re_set: RegexSet_::Invalid,
disable_sanitizations: false,
})
} else if ! had_bad && ! had_good {
t!("No regular expressions provided.");
Ok(RegexSet {
re_bytes,
re_set: RegexSet_::Everything,
disable_sanitizations: false,
})
} else {
Ok(RegexSet {
re_bytes,
re_set: RegexSet_::Regex(
Regex {
re: String::new(),
regex: regex::RegexBuilder::new(
&Hir::alternation(regexes).to_string())
.build()?,
disable_sanitizations: false,
}),
disable_sanitizations: false,
})
}
}
pub fn from_bytes<'a, I, RE>(res: I) -> Result<Self>
where I: IntoIterator<Item=RE>,
RE: Borrow<&'a [u8]>,
{
let mut have_valid_utf8 = false;
let mut have_invalid_utf8 = false;
let mut re_bytes = Vec::new();
let re_set = Self::new(
res
.into_iter()
.scan((&mut have_valid_utf8, &mut have_invalid_utf8),
|(valid, invalid), re|
{
re_bytes.push(re.borrow().to_vec());
if let Ok(re) = std::str::from_utf8(re.borrow()) {
**valid = true;
Some(Some(re))
} else {
**invalid = true;
Some(None)
}
})
.flatten());
if !have_valid_utf8 && have_invalid_utf8 {
Ok(RegexSet {
re_bytes,
re_set: RegexSet_::Invalid,
disable_sanitizations: false,
})
} else {
re_set.map(|mut r| { r.re_bytes = re_bytes; r })
}
}
pub fn as_bytes(&self) -> &[Vec<u8>] {
&self.re_bytes
}
pub fn from_signature(sig: &Signature) -> Result<Self>
{
use SignatureType::*;
match sig.typ() {
GenericCertification => (),
PersonaCertification => (),
CasualCertification => (),
PositiveCertification => (),
t => return Err(
Error::InvalidArgument(
format!(
"Expected a certification signature, found a {}",
t))
.into()),
}
if sig.trust_signature().is_none() {
return Err(
Error::InvalidArgument(
"Expected a trust signature, \
but the signature does not include \
a valid Trust Signature subpacket".into())
.into());
}
Self::from_bytes(sig.regular_expressions())
}
pub fn everything() -> Self
{
Self {
re_bytes: vec![vec![]],
re_set: RegexSet_::Everything,
disable_sanitizations: false,
}
}
pub fn matches_everything(&self) -> bool {
matches!(self.re_set, RegexSet_::Everything)
}
pub fn disable_sanitizations(&mut self, allowed: bool) {
self.disable_sanitizations = allowed;
if let RegexSet_::Regex(ref mut re) = self.re_set {
re.disable_sanitizations(allowed);
}
}
pub fn is_match(&self, s: &str) -> bool {
if ! self.disable_sanitizations && s.chars().any(char::is_control) {
return false;
}
match self.re_set {
RegexSet_::Regex(ref re) =>
re.is_match_clean(s),
RegexSet_::Invalid =>
false,
RegexSet_::Everything =>
true,
}
}
pub fn matches_userid(&self, u: &UserID) -> bool
{
if let Ok(u) = std::str::from_utf8(u.value()) {
self.is_match(u)
} else {
false
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn regex() -> Result<()> {
fn a(regex: &str, matches: &[(bool, &str)]) {
eprint!("{} -> ", regex);
let mut compiled = Regex::new(regex).unwrap();
compiled.disable_sanitizations(true);
eprintln!("{:?}", compiled);
for &(matches, text) in matches {
assert_eq!(matches, compiled.is_match(text),
"regex: {}\n text: {:?} should{} match",
regex, text, if matches { "" } else { " not" });
}
}
fn f(regex: &str) {
eprint!("{} -> ", regex);
let compiled = Regex::new(regex);
assert!(compiled.is_err());
eprintln!("failed (expected)");
}
a("xab+y", &[
(true, "xaby"),
(true, "xabby"),
(false, "xababy"),
]);
a("x(ab+)y", &[
(false, "xy"),
(false, "xay"),
(true, "xaby"),
(true, "xabby"),
(true, "xabbby"),
(false, "xababy"),
]);
a("x(ab)+y", &[
(false, "xy"),
(true, "xaby"),
(false, "xabby"),
(true, "xababy"),
(true, "xabababy"),
(false, "x(ab)y"),
]);
a("", &[
(true, "s"),
(true, "ss"),
]);
a("s", &[
(true, "s"),
(true, "ss"),
(false, "a"),
(true, "hello, my prettiessss"),
(false, "S"),
]);
a("ss", &[
(false, "s"),
(true, "ss"),
(true, "sss"),
(false, "this has lots of ses, but not two ses together"),
(true, "halloss"),
]);
a("a|b", &[
(true, "a"),
(true, "b"),
(false, "c"),
(true, "xxxaxxxbxxx"),
]);
a("a|b|c", &[
(true, "a"),
(true, "b"),
(true, "c"),
(false, "d"),
(true, "xxxaxxxbxxx"),
]);
a("|a", &[
(true, "a"),
(true, "b"),
]);
a("a|", &[
(true, "a"),
(true, "b"),
]);
a("|a|b", &[
(true, "a"),
(true, "b"),
(true, "c"),
]);
a("|a|b|c|d", &[
(true, "a"),
(true, "b"),
(true, "c"),
(true, "d"),
(true, "eeee"),
]);
a("a|b|", &[
(true, "a"),
(true, "b"),
(true, "c"),
]);
a("a|b|c|", &[
(true, "a"),
(true, "b"),
(true, "c"),
(true, "d"),
(true, "eeee"),
]);
a("|", &[
(true, "a"),
(true, "b"),
(true, "c"),
(true, "d"),
(true, "eeee"),
]);
a("|a|", &[
(true, "a"),
(true, "b"),
(true, "c"),
(true, "d"),
(true, "eeee"),
]);
a("|a|b|", &[
(true, "a"),
(true, "b"),
(true, "c"),
(true, "d"),
(true, "eeee"),
]);
a("(a|)|b", &[
(true, "a"),
(true, "b"),
]);
a("(a|b|()+)", &[
(true, "a"),
(true, "b"),
]);
a("(a|b|(())+)", &[
(true, "a"),
(true, "b"),
]);
a("(a|b|(()())())", &[
(true, "a"),
(true, "b"),
]);
a("(a|b|(()())())|", &[
(true, "a"),
(true, "b"),
]);
a("ab|cd", &[
(true, "abd"),
(true, "acd"),
(true, "abcd"),
(false, "ad"),
(false, "b"),
(false, "c"),
(false, "bb"),
]);
a("a*", &[
(true, ""),
(true, "a"),
(true, "aa"),
(true, "b"),
]);
a("xa*y", &[
(true, "xy"),
(true, "xay"),
(true, "xaay"),
(false, "y"),
(false, "ay"),
(false, "aay"),
(false, "x y"),
(false, "x ay"),
(false, "x aay"),
]);
f("*");
a("a+", &[
(false, ""),
(true, "a"),
(true, "aa"),
(false, "b"),
(true, "baab"),
(true, "by ab"),
(true, "baa b"),
]);
a("ab+", &[
(false, ""),
(false, "a"),
(false, "b"),
(true, "ab"),
(false, "bb"),
(true, "baab"),
(true, "by ab"),
(false, "baa b"),
]);
f("+");
a("a?", &[
(true, ""),
(true, "a"),
(true, "aa"),
(true, "aaa"),
(true, "b"),
(true, "baab"),
(true, "by ab"),
(true, "baa b"),
]);
a("xa?y", &[
(false, ""),
(true, "xy"),
(false, "a"),
(true, "xay"),
(false, "aa"),
(false, "xaay"),
(false, "b"),
(false, "bxaayb"),
(true, "by xayb"),
(true, "baxay b"),
]);
f("?");
f("a*?");
a("a*b?c+", &[
(false, ""),
(true, "c"),
(true, "abc"),
(true, "aabbcc"),
(false, "aab"),
(true, "aaaaaabcccccccc"),
]);
f("a?*+");
a("a?|b+", &[
(true, ""),
(true, "aaa"),
(true, "bbb"),
(true, "abaa"),
]);
a("a+|b+", &[
(false, ""),
(true, "a"),
(true, "aaa"),
(true, "b"),
(true, "bbb"),
(true, "abaa"),
]);
a("a+|b+|c+", &[
(false, ""),
(true, "a"),
(true, "aaa"),
(true, "b"),
(true, "bbb"),
(true, "abaa"),
(true, "c"),
(true, "ccc"),
(true, "abaaccc"),
]);
a("xa+|b+|c+y", &[
(false, ""),
(true, "xa"),
(true, "xaa"),
(true, "b"),
(true, "bb"),
(true, "cy"),
(true, "ccy"),
(false, "a"),
(false, "aaa"),
(false, "c"),
(false, "ccc"),
]);
a("xa+y|sb+u", &[
(false, ""),
(true, "xay"),
(true, "xaay"),
(true, "sbu"),
(true, "sbbu"),
(true, "xysbu"),
(false, "a"),
(false, "aaa"),
(false, "xyu"),
(false, "ccc"),
]);
a("a*|a+|ab+cd+|", &[
(true, ""),
]);
a("()", &[
(true, ""),
(true, "xyzzy"),
]);
a("(())", &[
(true, ""),
(true, "xyzzy"),
]);
a("((()))", &[
(true, ""),
(true, "xyzzy"),
]);
f("((())");
f("((())))");
a("(a)", &[
(true, "a"),
(true, "(a)"),
(false, "b"),
]);
a("x(a)y", &[
(false, "xy"),
(true, "xay"),
(false, "x(a)y"),
(true, "(xay)"),
(false, "a"),
(false, "yax"),
]);
a("x(ab)y", &[
(false, "xy"),
(false, "xay"),
(false, "xby"),
(true, "xaby"),
(false, "x(ab)y"),
(true, "(xaby)"),
]);
a("x(ab)(cd)y", &[
(true, "xabcdy"),
(true, "zxabcdyz"),
]);
a("a(bc)d(ef)g", &[
(true, "abcdefg"),
(true, "xabcdefgy"),
(false, "xa(bc)d(ef)gy"),
]);
a("a((bc))d((ef))g", &[
(true, "abcdefg"),
(true, "xabcdefgy"),
(false, "xa(bc)d(ef)gy"),
]);
a("a(b(c)d)e", &[
(true, "abcde"),
(true, "xabcdey"),
(false, "xa(b(c)d)ey"),
]);
a("x(a|b)y", &[
(false, "xy"),
(true, "xay"),
(true, "xby"),
(false, "xaay"),
(false, "xbby"),
(false, "xaby"),
(false, "xaaby"),
(false, "xabby"),
(false, "xaabby"),
(false, "xcy"),
]);
a("x(a|bc)y", &[
(false, "xy"),
(true, "xay"),
(false, "xby"),
(true, "xbcy"),
(false, "xaay"),
(false, "xbby"),
(false, "xaby"),
(false, "xabcy"),
(false, "xabby"),
(false, "xaabby"),
(false, "xcy"),
(false, "xacy"),
]);
a("x(a|b|c)y", &[
(false, "xy"),
(true, "xay"),
(true, "xby"),
(true, "xcy"),
(false, "xaay"),
(false, "xbby"),
(false, "xaby"),
(false, "xabcy"),
(false, "xabby"),
(false, "xaabby"),
(false, "xacy"),
]);
a("x(a|b)(c|d)y", &[
(false, "xy"),
(false, "xay"),
(false, "xby"),
(false, "xcy"),
(false, "xdy"),
(false, "xaay"),
(false, "xbby"),
(false, "xccy"),
(false, "xddy"),
(false, "xaby"),
(false, "xcdy"),
(true, "xacy"),
(true, "xady"),
(true, "xbcy"),
(true, "xbdy"),
(false, "xabcy"),
(false, "xabby"),
(false, "xaabby"),
]);
a("x(a+|b+)y", &[
(false, "xy"),
(true, "xay"),
(true, "xby"),
(true, "xaay"),
(true, "xbby"),
(false, "xaby"),
(false, "xaaby"),
(false, "xabby"),
(false, "xaabby"),
(false, "xcy"),
]);
a(".", &[
(false, ""),
(true, "a"),
(true, "ab"),
(true, "ab\nc"),
(true, "ab.c"),
]);
a("x.y", &[
(false, ""),
(false, "xy"),
(true, "xay"),
(true, "x\ny"),
(true, "x.y"),
(false, "x..y"),
]);
a("^", &[
(true, ""),
(true, "xx"),
]);
a("^abc", &[
(false, ""),
(true, "abcdef"),
(false, "xabcdef"),
(false, "\nabcdef"),
]);
a("(^abc|^def)", &[
(false, ""),
(true, "abcd"),
(true, "defg"),
(false, "xabcd"),
(false, "xdefg"),
(false, "^abc"),
(false, "^(abc|def)"),
(false, "\nabcdef"),
]);
a("(^abc|def)", &[
(false, ""),
(true, "abcd"),
(true, "defg"),
(false, "xabcd"),
(true, "xdefg"),
(false, "^abc"),
(true, "^(abc|def)"),
(false, "\nabcde"),
]);
a("^^", &[
(true, ""),
(true, "abcdef"),
]);
a("^abc^", &[
(false, ""),
(false, "abcdef"),
(false, "xabcdef"),
(false, "abc\n"),
(false, "\nabc\n"),
(false, "^abc^"),
]);
a("$", &[
(true, ""),
(true, "abc"),
]);
a("abc$", &[
(false, ""),
(true, "abc"),
(false, "abcx"),
(false, "abc\n"),
(false, "abc$"),
]);
a("abc$$", &[
(false, ""),
(true, "abc"),
(false, "abcx"),
(false, "abc\n"),
(false, "abc$"),
]);
a("(abc$)x", &[
(false, ""),
(false, "abc"),
(false, "abcx"),
(false, "abc\nx"),
(false, "abc$x"),
]);
a("abc$|def$", &[
(false, ""),
(true, "abc"),
(false, "abcx"),
(false, "abc\n"),
(false, "abc$"),
(true, "def"),
(false, "defx"),
(false, "def\n"),
(false, "def$"),
(true, "abcdef"),
]);
a("\\|", &[
(true, "|"),
(false, ""),
(false, "a"),
]);
a("\\*", &[
(true, "*"),
(false, ""),
(false, "a"),
]);
a("\\+", &[
(true, "+"),
(false, ""),
(false, "a"),
]);
a("\\?", &[
(true, "?"),
(false, ""),
(false, "a"),
]);
a("\\.", &[
(true, "."),
(false, ""),
(false, "a"),
]);
a("\\^", &[
(true, "^"),
(false, ""),
(false, "a"),
]);
a("\\$", &[
(true, "$"),
(false, ""),
(false, "a"),
]);
a("\\\\", &[
(true, "\\"),
(false, ""),
(false, "a"),
]);
a("\\[", &[
(true, "["),
(false, ""),
(false, "a"),
]);
a("\\]", &[
(true, "]"),
(false, ""),
(false, "a"),
]);
a("\\-", &[
(true, "-"),
(false, ""),
(false, "a"),
]);
f("\\");
a("[a]", &[
(true, "a"),
(false, "b"),
]);
a("[abc]", &[
(true, "a"),
(true, "b"),
(true, "c"),
(false, "d"),
]);
a("[a-c]", &[
(true, "a"),
(true, "b"),
(true, "c"),
(false, "d"),
]);
a("[xa-c]", &[
(true, "a"),
(true, "b"),
(true, "c"),
(true, "x"),
(false, "d"),
]);
a("[a-cxyz]", &[
(true, "a"),
(true, "b"),
(true, "c"),
(true, "x"),
(false, "d"),
]);
a("[a-c]x", &[
(false, "a"),
(false, "b"),
(false, "c"),
(false, "x"),
(true, "ax"),
(true, "bx"),
(true, "cx"),
(false, "d"),
(false, "dx"),
]);
a("[a-cxy]", &[
(true, "a"),
(true, "b"),
(true, "c"),
(true, "x"),
(true, "y"),
(false, "d"),
]);
a("[a-c]xy", &[
(false, "a"),
(false, "b"),
(false, "c"),
(false, "x"),
(false, "ax"),
(false, "bx"),
(false, "cx"),
(true, "axy"),
(true, "bxy"),
(true, "cxy"),
(false, "d"),
]);
a("[a-cxyz]", &[
(true, "a"),
(true, "b"),
(true, "c"),
(true, "x"),
(true, "y"),
(true, "z"),
(false, "d"),
]);
a("[a-c]xyz", &[
(false, "a"),
(false, "b"),
(false, "c"),
(false, "x"),
(false, "ax"),
(false, "bx"),
(false, "cx"),
(false, "axy"),
(false, "bxy"),
(false, "cxy"),
(true, "axyz"),
(true, "bxyz"),
(true, "cxyz"),
(false, "d"),
]);
a("xyz[a-c]", &[
(false, "a"),
(false, "b"),
(false, "c"),
(false, "x"),
(false, "xa"),
(false, "xb"),
(false, "xc"),
(false, "xya"),
(false, "xyb"),
(false, "xyc"),
(true, "xyza"),
(true, "xyzb"),
(true, "xyzc"),
(false, "d"),
]);
a("[xyza-c]", &[
(true, "a"),
(true, "b"),
(true, "c"),
(true, "x"),
(true, "y"),
(true, "z"),
(false, "d"),
]);
a("[xya-cyz]", &[
(true, "a"),
(true, "b"),
(true, "c"),
(true, "x"),
(true, "y"),
(true, "z"),
(false, "d"),
]);
a("[x-za-c]", &[
(true, "a"),
(true, "b"),
(true, "c"),
(true, "x"),
(true, "y"),
(true, "z"),
(false, "d"),
]);
a("[x-zmna-c]", &[
(true, "a"),
(true, "b"),
(true, "c"),
(true, "x"),
(true, "y"),
(true, "z"),
(true, "m"),
(true, "n"),
(false, "d"),
]);
a("[-]", &[
(true, "-"),
(false, "d"),
]);
a("[a-]", &[
(true, "-"),
(true, "a"),
(false, "d"),
]);
a("[-b]", &[
(true, "-"),
(true, "b"),
(false, "d"),
]);
a("[-bd-g]", &[
(false, "a"),
(true, "-"),
(true, "b"),
(true, "d"),
(true, "f"),
]);
a("[bd-g-]", &[
(false, "a"),
(true, "-"),
(true, "b"),
(true, "d"),
(true, "f"),
]);
a("[9-0]", &[
(false, "a"),
(false, "-"),
(true, "9"),
(true, "0"),
(true, "5"),
]);
a("[^a]", &[
(false, "a"),
(true, "b"),
]);
a("[^abc]", &[
(false, "a"),
(false, "b"),
(false, "c"),
(true, "d"),
]);
a("[^a-c]", &[
(false, "a"),
(false, "b"),
(false, "c"),
(true, "d"),
]);
a("[^xa-c]", &[
(false, "a"),
(false, "b"),
(false, "c"),
(false, "x"),
(true, "d"),
]);
a("[^a-cxyz]", &[
(false, "a"),
(false, "b"),
(false, "c"),
(false, "x"),
(true, "d"),
]);
a("[^a-c]x", &[
(false, "a"),
(false, "b"),
(false, "c"),
(false, "x"),
(false, "ax"),
(false, "bx"),
(false, "cx"),
(false, "d"),
(true, "dx"),
]);
a("[^a-cxy]", &[
(false, "a"),
(false, "b"),
(false, "c"),
(false, "x"),
(false, "y"),
(true, "d"),
]);
a("[^a-c]xy", &[
(false, "a"),
(false, "b"),
(false, "c"),
(false, "x"),
(false, "ax"),
(false, "bx"),
(false, "cx"),
(false, "axy"),
(false, "bxy"),
(false, "cxy"),
(true, "dxy"),
(false, "d"),
]);
a("[^a-cxyz]", &[
(false, "a"),
(false, "b"),
(false, "c"),
(false, "x"),
(false, "y"),
(false, "z"),
(true, "d"),
]);
a("[^a-c]xyz", &[
(false, "a"),
(false, "b"),
(false, "c"),
(false, "x"),
(false, "ax"),
(false, "bx"),
(false, "cx"),
(false, "axy"),
(false, "bxy"),
(false, "cxy"),
(false, "axyz"),
(false, "bxyz"),
(false, "cxyz"),
(true, "dxyz"),
(false, "d"),
]);
a("xyz[^a-c]", &[
(false, "a"),
(false, "b"),
(false, "c"),
(false, "x"),
(false, "xa"),
(false, "xb"),
(false, "xc"),
(false, "xya"),
(false, "xyb"),
(false, "xyc"),
(false, "xyza"),
(false, "xyzb"),
(false, "xyzc"),
(true, "xyzd"),
(false, "d"),
]);
a("[^xyza-c]", &[
(false, "a"),
(false, "b"),
(false, "c"),
(false, "x"),
(false, "y"),
(false, "z"),
(true, "d"),
]);
a("[^xya-cyz]", &[
(false, "a"),
(false, "b"),
(false, "c"),
(false, "x"),
(false, "y"),
(false, "z"),
(true, "d"),
]);
a("[^x-za-c]", &[
(false, "a"),
(false, "b"),
(false, "c"),
(false, "x"),
(false, "y"),
(false, "z"),
(true, "d"),
]);
a("[^x-zmna-c]", &[
(false, "a"),
(false, "b"),
(false, "c"),
(false, "x"),
(false, "y"),
(false, "z"),
(false, "m"),
(false, "n"),
(true, "d"),
]);
a("[^-]", &[
(false, "-"),
(true, "d"),
]);
a("[^a-]", &[
(false, "-"),
(false, "a"),
(true, "d"),
]);
a("[^-b]", &[
(false, "-"),
(false, "b"),
(true, "d"),
]);
a("[^-bd-g]", &[
(true, "a"),
(false, "-"),
(false, "b"),
(false, "d"),
(false, "f"),
]);
a("[^bd-g-]", &[
(true, "a"),
(false, "-"),
(false, "b"),
(false, "d"),
(false, "f"),
]);
a("[a|b]", &[
(true, "a"),
(true, "|"),
(false, "c"),
]);
a("[a\\|b]", &[
(true, "a"),
(true, "|"),
(true, "\\"),
(false, "c"),
]);
a("[a(b]", &[
(true, "a"),
(true, "("),
(false, "c"),
]);
a("[a)b]", &[
(true, "a"),
(true, ")"),
(false, "c"),
]);
a("[a^b]", &[
(true, "a"),
(true, "^"),
(false, "c"),
]);
f("[]");
f("[^]");
a("[^]]", &[
(true, "a"),
(false, "]"),
(true, "^"),
]);
a("[]]", &[
(false, "a"),
(true, "]"),
]);
a("[][]", &[
(false, "a"),
(true, "["),
(true, "]"),
]);
a("[^][]", &[
(true, "a"),
(false, "["),
(false, "]"),
]);
a("[^^]", &[
(true, "a"),
(false, "^"),
(true, "c"),
]);
a("a-z", &[
(true, "a-z"),
(false, "a"),
(false, "-"),
(false, "z"),
(false, "c"),
]);
a("a|-|z", &[
(true, "a"),
(true, "-"),
(true, "z"),
(false, "c"),
]);
Ok(())
}
#[test]
fn regex_set() -> Result<()> {
let re = RegexSet::new(&[ "ab", "cd" ])?;
assert!(re.is_match("ab"));
assert!(re.is_match("cdef"));
assert!(!re.is_match("xxx"));
let re = RegexSet::new(&[ "cd$", "^ab" ])?;
assert!(re.is_match("abxx"));
assert!(! re.is_match("xabxx"));
assert!(re.is_match("xxcd"));
assert!(! re.is_match("xxcdx"));
assert!(re.is_match("abcdx"));
let re = RegexSet::new(&[ "[ab", "cd]", "x" ])?;
assert!(!re.is_match("a"));
assert!(!re.is_match("ab"));
assert!(!re.is_match("[ab"));
assert!(!re.is_match("c"));
assert!(!re.is_match("cd"));
assert!(!re.is_match("cd]"));
assert!(re.is_match("x"));
let re = RegexSet::new(&[ "[ab", "cd]" ])?;
assert!(!re.is_match("a"));
assert!(!re.is_match("ab"));
assert!(!re.is_match("[ab"));
assert!(!re.is_match("c"));
assert!(!re.is_match("cd"));
assert!(!re.is_match("cd]"));
assert!(!re.is_match("x"));
let s: [&str; 0] = [];
let re = RegexSet::new(&s)?;
assert!(re.is_match("a"));
assert!(re.is_match("ab"));
assert!(re.is_match("[ab"));
assert!(re.is_match("c"));
assert!(re.is_match("cd"));
assert!(re.is_match("cd]"));
assert!(re.is_match("x"));
let re = RegexSet::new(&[ "ab|", "cd" ])?;
assert!(re.is_match("a"));
assert!(re.is_match("b"));
assert!(re.is_match("x"));
assert!(re.is_match("xyx"));
assert!(re.is_match(""));
Ok(())
}
#[test]
fn regex_set_sequoia() -> Result<()> {
let re = RegexSet::new(&["<[^>]+[@.]sequoia-pgp\\.org>$"])?;
dbg!(&re);
assert!(re.is_match("<justus@sequoia-pgp.org>"));
assert!(!re.is_match("<justus@gnupg.org>"));
Ok(())
}
#[test]
fn regex_set_sequoia_nodash() -> Result<()> {
let re = RegexSet::new(&["<[^>]+[@.]sequoiapgp\\.org>$"])?;
dbg!(&re);
assert!(re.is_match("<justus@sequoiapgp.org>"));
assert!(!re.is_match("<justus@gnupg.org>"));
Ok(())
}
}