#![allow(dead_code)]
use regex_syntax::ast::{ClassBracketed, ClassPerl, ClassUnicode, Literal, Span};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Error {
kind: ErrorKind,
pattern: String,
span: Span,
}
impl Error {
pub fn kind(&self) -> &ErrorKind {
&self.kind
}
pub fn pattern(&self) -> &str {
&self.pattern
}
pub fn span(&self) -> &Span {
&self.span
}
pub fn auxiliary_span(&self) -> Option<&Span> {
use self::ErrorKind::*;
match self.kind {
FlagDuplicate { ref original } => Some(original),
FlagRepeatedNegation { ref original, .. } => Some(original),
GroupNameDuplicate { ref original, .. } => Some(original),
_ => None,
}
}
}
#[non_exhaustive]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ErrorKind {
CaptureLimitExceeded,
ClassEscapeInvalid,
ClassRangeInvalid,
ClassRangeLiteral,
ClassUnclosed,
DecimalEmpty,
DecimalInvalid,
EscapeHexEmpty,
EscapeHexInvalid,
EscapeHexInvalidDigit,
EscapeUnexpectedEof,
EscapeUnrecognized,
FlagDanglingNegation,
FlagDuplicate {
original: Span,
},
FlagRepeatedNegation {
original: Span,
},
FlagUnexpectedEof,
FlagUnrecognized,
GroupNameDuplicate {
original: Span,
},
GroupNameEmpty,
GroupNameInvalid,
GroupNameUnexpectedEof,
GroupUnclosed,
GroupUnopened,
NestLimitExceeded(u32),
RepetitionCountInvalid,
RepetitionCountDecimalEmpty,
RepetitionCountUnclosed,
RepetitionMissing,
SpecialWordBoundaryUnclosed,
SpecialWordBoundaryUnrecognized,
SpecialWordOrRepetitionUnexpectedEof,
UnicodeClassInvalid,
UnsupportedBackreference,
UnsupportedLookAround,
UnsupportedResharpRegex,
UnsupportedLazyQuantifier,
ComplementGroupExpected,
}
impl core::fmt::Display for ErrorKind {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
use self::ErrorKind::*;
match *self {
CaptureLimitExceeded => write!(
f,
"exceeded the maximum number of \
capturing groups ({})",
u32::MAX
),
ClassEscapeInvalid => {
write!(f, "invalid escape sequence found in character class")
}
ClassRangeInvalid => write!(
f,
"invalid character class range, \
the start must be <= the end"
),
ClassRangeLiteral => {
write!(f, "invalid range boundary, must be a literal")
}
ClassUnclosed => write!(f, "unclosed character class"),
DecimalEmpty => write!(f, "decimal literal empty"),
DecimalInvalid => write!(f, "decimal literal invalid"),
EscapeHexEmpty => write!(f, "hexadecimal literal empty"),
EscapeHexInvalid => {
write!(f, "hexadecimal literal is not a Unicode scalar value")
}
EscapeHexInvalidDigit => write!(f, "invalid hexadecimal digit"),
EscapeUnexpectedEof => write!(
f,
"incomplete escape sequence, \
reached end of pattern prematurely"
),
EscapeUnrecognized => write!(f, "unrecognized escape sequence"),
FlagDanglingNegation => {
write!(f, "dangling flag negation operator")
}
FlagDuplicate { .. } => write!(f, "duplicate flag"),
FlagRepeatedNegation { .. } => {
write!(f, "flag negation operator repeated")
}
FlagUnexpectedEof => {
write!(f, "expected flag but got end of regex")
}
FlagUnrecognized => write!(f, "unrecognized flag"),
GroupNameDuplicate { .. } => {
write!(f, "duplicate capture group name")
}
GroupNameEmpty => write!(f, "empty capture group name"),
GroupNameInvalid => write!(f, "invalid capture group character"),
GroupNameUnexpectedEof => write!(f, "unclosed capture group name"),
GroupUnclosed => write!(f, "unclosed group"),
GroupUnopened => write!(f, "unopened group"),
NestLimitExceeded(limit) => write!(
f,
"exceed the maximum number of \
nested parentheses/brackets ({})",
limit
),
RepetitionCountInvalid => write!(
f,
"invalid repetition count range, \
the start must be <= the end"
),
RepetitionCountDecimalEmpty => {
write!(f, "repetition quantifier expects a valid decimal")
}
RepetitionCountUnclosed => {
write!(f, "unclosed counted repetition")
}
RepetitionMissing => {
write!(f, "repetition operator missing expression")
}
SpecialWordBoundaryUnclosed => {
write!(
f,
"special word boundary assertion is either \
unclosed or contains an invalid character",
)
}
SpecialWordBoundaryUnrecognized => {
write!(
f,
"unrecognized special word boundary assertion, \
valid choices are: start, end, start-half \
or end-half",
)
}
SpecialWordOrRepetitionUnexpectedEof => {
write!(
f,
"found either the beginning of a special word \
boundary or a bounded repetition on a \\b with \
an opening brace, but no closing brace",
)
}
UnicodeClassInvalid => {
write!(f, "invalid Unicode character class")
}
UnsupportedBackreference => {
write!(f, "backreferences are not supported")
}
UnsupportedLookAround => write!(
f,
"look-around, including look-ahead and look-behind, \
is not supported"
),
UnsupportedResharpRegex => write!(f, "this pattern is not supported"),
UnsupportedLazyQuantifier => {
write!(f, "lazy quantifiers are not supported")
}
ComplementGroupExpected => write!(f, "expected ( after ~ for complement group"),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct WithComments {
pub ast: Ast,
pub comments: Vec<Comment>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Comment {
pub span: Span,
pub comment: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Ast {
Empty(Box<Span>),
Flags(Box<SetFlags>),
Literal(Box<Literal>),
Dot(Box<Span>),
Top(Box<Span>),
Assertion(Box<Assertion>),
ClassUnicode(Box<ClassUnicode>),
ClassPerl(Box<ClassPerl>),
ClassBracketed(Box<ClassBracketed>),
Repetition(Box<Repetition>),
Group(Box<Group>),
Alternation(Box<Alternation>),
Concat(Box<Concat>),
Intersection(Box<Intersection>),
Complement(Box<Complement>),
Lookaround(Box<Lookaround>),
}
impl Ast {
pub fn empty(span: Span) -> Ast {
Ast::Empty(Box::new(span))
}
pub fn flags(e: SetFlags) -> Ast {
Ast::Flags(Box::new(e))
}
pub fn literal(e: Literal) -> Ast {
Ast::Literal(Box::new(e))
}
pub fn dot(span: Span) -> Ast {
Ast::Dot(Box::new(span))
}
pub fn top(span: Span) -> Ast {
Ast::Top(Box::new(span))
}
pub fn assertion(e: Assertion) -> Ast {
Ast::Assertion(Box::new(e))
}
pub fn class_unicode(e: ClassUnicode) -> Ast {
Ast::ClassUnicode(Box::new(e))
}
pub fn class_perl(e: ClassPerl) -> Ast {
Ast::ClassPerl(Box::new(e))
}
pub fn class_bracketed(e: ClassBracketed) -> Ast {
Ast::ClassBracketed(Box::new(e))
}
pub fn repetition(e: Repetition) -> Ast {
Ast::Repetition(Box::new(e))
}
pub fn group(e: Group) -> Ast {
match &e.kind {
GroupKind::CaptureIndex(_) => Ast::Group(Box::new(e)),
GroupKind::CaptureName {
starts_with_p: _,
name: _,
} => Ast::Group(Box::new(e)),
GroupKind::NonCapturing(_flags) => Ast::Group(Box::new(e)),
GroupKind::Lookaround(kind) => {
let look = Lookaround {
kind: kind.clone(),
span: e.span,
ast: e.ast,
};
Ast::lookaround(look)
}
GroupKind::Complement => {
let g = Complement {
span: e.span,
ast: e.ast,
};
Ast::complement(g)
}
}
}
pub fn alternation(e: Alternation) -> Ast {
Ast::Alternation(Box::new(e))
}
pub fn concat(e: Concat) -> Ast {
Ast::Concat(Box::new(e))
}
pub fn span(&self) -> &Span {
match *self {
Ast::Empty(ref span) => span,
Ast::Flags(ref x) => &x.span,
Ast::Literal(ref x) => &x.span,
Ast::Dot(ref span) => span,
Ast::Top(ref span) => span,
Ast::Assertion(ref x) => &x.span,
Ast::ClassUnicode(ref x) => &x.span,
Ast::ClassPerl(ref x) => &x.span,
Ast::ClassBracketed(ref x) => &x.span,
Ast::Repetition(ref x) => &x.span,
Ast::Group(ref x) => &x.span,
Ast::Alternation(ref x) => &x.span,
Ast::Concat(ref x) => &x.span,
Ast::Intersection(ref x) => &x.span,
Ast::Complement(ref x) => &x.span,
Ast::Lookaround(ref x) => &x.span,
}
}
pub fn is_empty(&self) -> bool {
matches!(*self, Ast::Empty(_))
}
fn has_subexprs(&self) -> bool {
match *self {
Ast::Empty(_)
| Ast::Flags(_)
| Ast::Literal(_)
| Ast::Dot(_)
| Ast::Top(_)
| Ast::Assertion(_)
| Ast::ClassUnicode(_)
| Ast::ClassPerl(_) => false,
Ast::ClassBracketed(_)
| Ast::Repetition(_)
| Ast::Group(_)
| Ast::Alternation(_)
| Ast::Intersection(_)
| Ast::Lookaround(_)
| Ast::Complement(_)
| Ast::Concat(_) => true,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Alternation {
pub span: Span,
pub asts: Vec<Ast>,
}
impl Alternation {
pub fn into_ast(mut self) -> Ast {
match self.asts.len() {
0 => Ast::empty(self.span),
1 => self.asts.pop().unwrap(),
_ => Ast::alternation(self),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Concat {
pub span: Span,
pub asts: Vec<Ast>,
}
impl Concat {
pub fn into_ast(mut self) -> Ast {
match self.asts.len() {
0 => Ast::empty(self.span),
1 => self.asts.pop().unwrap(),
_ => Ast::concat(self),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Assertion {
pub span: Span,
pub kind: AssertionKind,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum AssertionKind {
StartLine,
EndLine,
StartText,
EndText,
WordBoundary,
NotWordBoundary,
WordBoundaryStart,
WordBoundaryEnd,
WordBoundaryStartAngle,
WordBoundaryEndAngle,
WordBoundaryStartHalf,
WordBoundaryEndHalf,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Repetition {
pub span: Span,
pub op: RepetitionOp,
pub greedy: bool,
pub ast: Box<Ast>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RepetitionOp {
pub span: Span,
pub kind: RepetitionKind,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RepetitionKind {
ZeroOrOne,
ZeroOrMore,
OneOrMore,
Range(RepetitionRange),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RepetitionRange {
Exactly(u32),
AtLeast(u32),
Bounded(u32, u32),
}
impl RepetitionRange {
pub fn is_valid(&self) -> bool {
!matches!(*self, RepetitionRange::Bounded(s, e) if s > e)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Group {
pub span: Span,
pub kind: GroupKind,
pub ast: Box<Ast>,
}
impl Group {
pub fn flags(&self) -> Option<&Flags> {
match self.kind {
GroupKind::NonCapturing(ref flags) => Some(flags),
_ => None,
}
}
pub fn is_capturing(&self) -> bool {
match self.kind {
GroupKind::CaptureIndex(_) | GroupKind::CaptureName { .. } => true,
GroupKind::NonCapturing(_) => false,
GroupKind::Lookaround(_) => false,
GroupKind::Complement => false,
}
}
pub fn capture_index(&self) -> Option<u32> {
match self.kind {
GroupKind::CaptureIndex(i) => Some(i),
GroupKind::CaptureName { ref name, .. } => Some(name.index),
GroupKind::NonCapturing(_) => None,
GroupKind::Lookaround(_) => None,
GroupKind::Complement => None,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum GroupKind {
CaptureIndex(u32),
CaptureName {
starts_with_p: bool,
name: CaptureName,
},
NonCapturing(Flags),
Lookaround(LookaroundKind),
Complement,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CaptureName {
pub span: Span,
pub name: String,
pub index: u32,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SetFlags {
pub span: Span,
pub flags: Flags,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Flags {
pub span: Span,
pub items: Vec<FlagsItem>,
}
impl Flags {
pub fn add_item(&mut self, item: FlagsItem) -> Option<usize> {
for (i, x) in self.items.iter().enumerate() {
if x.kind == item.kind {
return Some(i);
}
}
self.items.push(item);
None
}
pub fn flag_state(&self, flag: Flag) -> Option<bool> {
let mut negated = false;
for x in &self.items {
match x.kind {
FlagsItemKind::Negation => {
negated = true;
}
FlagsItemKind::Flag(ref xflag) if xflag == &flag => {
return Some(!negated);
}
_ => {}
}
}
None
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FlagsItem {
pub span: Span,
pub kind: FlagsItemKind,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum FlagsItemKind {
Negation,
Flag(Flag),
}
impl FlagsItemKind {
pub fn is_negation(&self) -> bool {
matches!(*self, FlagsItemKind::Negation)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Flag {
CaseInsensitive,
MultiLine,
DotMatchesNewLine,
SwapGreed,
Unicode,
CRLF,
IgnoreWhitespace,
}
impl Ast {
pub fn intersection(e: Intersection) -> Ast {
Ast::Intersection(Box::new(e))
}
pub fn complement(e: Complement) -> Ast {
Ast::Complement(Box::new(e))
}
pub fn lookaround(e: Lookaround) -> Ast {
Ast::Lookaround(Box::new(e))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Intersection {
pub span: Span,
pub asts: Vec<Ast>,
}
impl Intersection {
pub fn into_ast(mut self) -> Ast {
match self.asts.len() {
0 => Ast::empty(self.span),
1 => self.asts.pop().unwrap(),
_ => Ast::intersection(self),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Complement {
pub span: Span,
pub ast: Box<Ast>,
}
impl Complement {
pub fn into_ast(self) -> Ast {
Ast::complement(self)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LookaroundKind {
PositiveLookahead,
NegativeLookahead,
PositiveLookbehind,
NegativeLookbehind,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Lookaround {
pub kind: LookaroundKind,
pub span: Span,
pub ast: Box<Ast>,
}
impl Lookaround {
pub fn into_ast(self) -> Ast {
Ast::lookaround(self)
}
}