use std::borrow::Cow;
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
use std::slice::Iter;
use ::ascii_tree::write_tree;
use bitflags::bitflags;
use bstr::{BStr, BString, ByteSlice, Utf8Error};
use crate::ast::cst2ast::Builder;
use crate::cst::SyntaxKind::{
ASCII_KW, BASE64WIDE_KW, BASE64_KW, FULLWORD_KW, NOCASE_KW, WIDE_KW,
XOR_KW,
};
use crate::cst::{CSTStream, Event};
use crate::{Parser, Span};
mod ascii_tree;
mod cst2ast;
mod errors;
#[cfg(test)]
mod tests;
pub mod dfs;
pub use errors::Error;
pub struct AST<'src> {
pub items: Vec<Item<'src>>,
errors: Vec<Error>,
}
pub enum Item<'src> {
Import(Import<'src>),
Include(Include<'src>),
Rule(Rule<'src>),
}
impl<'src> From<&'src str> for AST<'src> {
#[inline]
fn from(src: &'src str) -> Self {
AST::from(src.as_bytes())
}
}
impl<'src> From<&'src [u8]> for AST<'src> {
#[inline]
fn from(src: &'src [u8]) -> Self {
AST::from(Parser::new(src))
}
}
impl<'src> From<Parser<'src>> for AST<'src> {
fn from(parser: Parser<'src>) -> Self {
AST::new(parser.source(), parser)
}
}
impl<'src, I> From<CSTStream<'src, I>> for AST<'src>
where
I: Iterator<Item = Event>,
{
fn from(cst: CSTStream<'src, I>) -> Self {
AST::new(cst.source(), cst)
}
}
impl<'src> AST<'src> {
#[doc(hidden)]
pub fn new<I: Iterator<Item = Event>>(
src: &'src [u8],
events: I,
) -> AST<'src> {
Builder::new(src, events).build_ast()
}
#[inline]
pub fn items(&self) -> impl Iterator<Item = &Item<'src>> {
self.items.iter()
}
pub fn imports(&self) -> impl Iterator<Item = &Import<'src>> {
self.items.iter().filter_map(|item| {
if let Item::Import(import) = item {
Some(import)
} else {
None
}
})
}
pub fn rules(&self) -> impl Iterator<Item = &Rule<'src>> {
self.items.iter().filter_map(|item| {
if let Item::Rule(rule) = item {
Some(rule)
} else {
None
}
})
}
#[inline]
pub fn errors(&self) -> &[Error] {
self.errors.as_slice()
}
#[inline]
pub fn into_errors(self) -> Vec<Error> {
self.errors
}
}
impl Debug for AST<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
for rule in self.rules() {
write_tree(f, &ascii_tree::rule_ascii_tree(rule))?;
writeln!(f)?;
}
if !self.errors.is_empty() {
writeln!(f, "ERRORS:")?;
for err in &self.errors {
writeln!(f, "- {err:?}")?;
}
}
Ok(())
}
}
#[derive(Debug)]
pub struct Import<'src> {
span: Span,
pub module_name: &'src str,
}
#[derive(Debug)]
pub struct Include<'src> {
span: Span,
pub file_name: &'src str,
}
#[derive(Debug)]
pub struct Rule<'src> {
pub flags: RuleFlags,
pub identifier: Ident<'src>,
pub tags: Option<Vec<Ident<'src>>>,
pub meta: Option<Vec<Meta<'src>>>,
pub patterns: Option<Vec<Pattern<'src>>>,
pub condition: Expr<'src>,
}
bitflags! {
#[derive(Debug)]
pub struct RuleFlags: u8 {
const Private = 0x01;
const Global = 0x02;
}
}
#[derive(Debug)]
pub struct Meta<'src> {
pub identifier: Ident<'src>,
pub value: MetaValue<'src>,
}
#[derive(Debug)]
pub enum MetaValue<'src> {
Bool((bool, Span)),
Integer((i64, Span)),
Float((f64, Span)),
String((&'src str, Span)),
Bytes((BString, Span)),
}
impl Display for MetaValue<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Bool((v, _)) => write!(f, "{v}"),
Self::Integer((v, _)) => write!(f, "{v}"),
Self::Float((v, _)) => write!(f, "{v:.1}"),
Self::String((v, _)) => write!(f, "\"{v}\""),
Self::Bytes((v, _)) => write!(f, "\"{v}\""),
}
}
}
#[derive(Debug, Clone, Default)]
pub struct Ident<'src> {
span: Span,
#[doc(hidden)]
pub name: &'src str,
}
impl<'src> Ident<'src> {
#[doc(hidden)]
pub fn new(name: &'src str) -> Self {
Self { name, span: Default::default() }
}
pub fn starts_with(&self, pat: &str) -> bool {
self.name.starts_with(pat)
}
}
#[derive(Debug)]
pub struct IdentWithRange<'src> {
span: Span,
pub identifier: Ident<'src>,
pub range: Option<Range<'src>>,
}
#[derive(Debug)]
pub struct IdentWithIndex<'src> {
span: Span,
pub identifier: Ident<'src>,
pub index: Option<Expr<'src>>,
}
#[derive(Debug)]
pub enum Pattern<'src> {
Text(Box<TextPattern<'src>>),
Hex(Box<HexPattern<'src>>),
Regexp(Box<RegexpPattern<'src>>),
}
impl<'src> Pattern<'src> {
pub fn identifier(&self) -> &Ident<'src> {
match self {
Pattern::Text(p) => &p.identifier,
Pattern::Regexp(p) => &p.identifier,
Pattern::Hex(p) => &p.identifier,
}
}
pub fn modifiers(&self) -> &PatternModifiers<'src> {
match self {
Pattern::Text(p) => &p.modifiers,
Pattern::Hex(p) => &p.modifiers,
Pattern::Regexp(p) => &p.modifiers,
}
}
}
#[derive(Debug)]
pub struct TextPattern<'src> {
pub identifier: Ident<'src>,
pub text: LiteralString<'src>,
pub modifiers: PatternModifiers<'src>,
}
#[derive(Debug)]
pub struct RegexpPattern<'src> {
pub identifier: Ident<'src>,
pub regexp: Regexp<'src>,
pub modifiers: PatternModifiers<'src>,
}
#[derive(Debug, Default)]
pub struct HexPattern<'src> {
span: Span,
pub identifier: Ident<'src>,
pub sub_patterns: HexSubPattern,
pub modifiers: PatternModifiers<'src>,
}
impl<'src> HexPattern<'src> {
#[doc(hidden)]
pub fn new(ident: &'src str) -> Self {
Self {
identifier: Ident::new(ident),
span: Span::default(),
..Default::default()
}
}
}
#[derive(Debug, Default)]
pub struct HexSubPattern(pub Vec<HexToken>);
impl HexSubPattern {
#[inline]
pub fn iter(&self) -> impl Iterator<Item = &HexToken> {
self.0.iter()
}
#[inline]
pub fn len(&self) -> usize {
self.0.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
#[derive(Debug)]
pub enum HexToken {
Byte(HexByte),
NotByte(HexByte),
Alternative(Box<HexAlternative>),
Jump(HexJump),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HexByte {
span: Span,
pub value: u8,
pub mask: u8,
}
impl HexByte {
#[doc(hidden)]
pub fn new(value: u8, mask: u8) -> Self {
Self { value, mask, span: Span::default() }
}
}
#[derive(Debug, Default)]
pub struct HexAlternative {
span: Span,
pub alternatives: Vec<HexSubPattern>,
}
impl HexAlternative {
#[doc(hidden)]
pub fn new(alternatives: Vec<HexSubPattern>) -> Self {
Self { alternatives, span: Span::default() }
}
}
#[derive(Debug, Clone, Default)]
pub struct HexJump {
span: Span,
pub start: Option<u32>,
pub end: Option<u32>,
}
impl HexJump {
#[doc(hidden)]
pub fn new(start: Option<u32>, end: Option<u32>) -> Self {
Self { start, end, span: Span::default() }
}
}
impl Display for HexJump {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match (self.start, self.end) {
(Some(start), Some(end)) => write!(f, "[{start}-{end}]"),
(Some(start), None) => write!(f, "[{start}-]"),
(None, Some(end)) => write!(f, "[-{end}]"),
(None, None) => write!(f, "[-]"),
}
}
}
#[derive(Debug)]
pub struct Of<'src> {
span: Span,
pub quantifier: Quantifier<'src>,
pub items: OfItems<'src>,
pub anchor: Option<MatchAnchor<'src>>,
}
#[derive(Debug)]
pub struct ForOf<'src> {
span: Span,
pub quantifier: Quantifier<'src>,
pub pattern_set: PatternSet<'src>,
pub body: Expr<'src>,
}
#[derive(Debug)]
pub struct ForIn<'src> {
span: Span,
pub quantifier: Quantifier<'src>,
pub variables: Vec<Ident<'src>>,
pub iterable: Iterable<'src>,
pub body: Expr<'src>,
}
#[derive(Debug)]
pub enum OfItems<'src> {
PatternSet(PatternSet<'src>),
BoolExprTuple(Vec<Expr<'src>>),
}
#[derive(Debug)]
pub struct With<'src> {
span: Span,
pub declarations: Vec<WithDeclaration<'src>>,
pub body: Expr<'src>,
}
#[derive(Debug)]
pub struct WithDeclaration<'src> {
span: Span,
pub identifier: Ident<'src>,
pub expression: Expr<'src>,
}
#[derive(Debug)]
pub enum Quantifier<'src> {
None {
span: Span,
},
All {
span: Span,
},
Any {
span: Span,
},
Percentage(Expr<'src>),
Expr(Expr<'src>),
}
#[derive(Debug)]
pub enum Iterable<'src> {
Range(Range<'src>),
ExprTuple(Vec<Expr<'src>>),
Expr(Expr<'src>),
}
#[derive(Debug)]
pub enum PatternSet<'src> {
Them { span: Span },
Set(Vec<PatternSetItem<'src>>),
}
#[derive(Debug)]
pub struct PatternSetItem<'src> {
span: Span,
pub identifier: &'src str,
pub wildcard: bool,
}
impl PatternSetItem<'_> {
pub fn matches(&self, identifier: &Ident) -> bool {
if self.wildcard {
identifier.name.starts_with(self.identifier)
} else {
identifier.name == self.identifier
}
}
}
#[derive(Debug)]
pub enum Expr<'src> {
True {
span: Span,
},
False {
span: Span,
},
Filesize {
span: Span,
},
Entrypoint {
span: Span,
},
LiteralString(Box<LiteralString<'src>>),
LiteralInteger(Box<LiteralInteger<'src>>),
LiteralFloat(Box<LiteralFloat<'src>>),
Regexp(Box<Regexp<'src>>),
Ident(Box<Ident<'src>>),
PatternMatch(Box<PatternMatch<'src>>),
PatternCount(Box<IdentWithRange<'src>>),
PatternOffset(Box<IdentWithIndex<'src>>),
PatternLength(Box<IdentWithIndex<'src>>),
Lookup(Box<Lookup<'src>>),
FieldAccess(Box<NAryExpr<'src>>),
FuncCall(Box<FuncCall<'src>>),
Defined(Box<UnaryExpr<'src>>),
Not(Box<UnaryExpr<'src>>),
And(Box<NAryExpr<'src>>),
Or(Box<NAryExpr<'src>>),
Minus(Box<UnaryExpr<'src>>),
Add(Box<NAryExpr<'src>>),
Sub(Box<NAryExpr<'src>>),
Mul(Box<NAryExpr<'src>>),
Div(Box<NAryExpr<'src>>),
Mod(Box<NAryExpr<'src>>),
BitwiseNot(Box<UnaryExpr<'src>>),
Shl(Box<BinaryExpr<'src>>),
Shr(Box<BinaryExpr<'src>>),
BitwiseAnd(Box<BinaryExpr<'src>>),
BitwiseOr(Box<BinaryExpr<'src>>),
BitwiseXor(Box<BinaryExpr<'src>>),
Eq(Box<BinaryExpr<'src>>),
Ne(Box<BinaryExpr<'src>>),
Lt(Box<BinaryExpr<'src>>),
Gt(Box<BinaryExpr<'src>>),
Le(Box<BinaryExpr<'src>>),
Ge(Box<BinaryExpr<'src>>),
Contains(Box<BinaryExpr<'src>>),
IContains(Box<BinaryExpr<'src>>),
StartsWith(Box<BinaryExpr<'src>>),
IStartsWith(Box<BinaryExpr<'src>>),
EndsWith(Box<BinaryExpr<'src>>),
IEndsWith(Box<BinaryExpr<'src>>),
IEquals(Box<BinaryExpr<'src>>),
Matches(Box<BinaryExpr<'src>>),
Of(Box<Of<'src>>),
ForOf(Box<ForOf<'src>>),
ForIn(Box<ForIn<'src>>),
With(Box<With<'src>>),
}
#[derive(Debug, Default)]
pub struct PatternModifiers<'src> {
modifiers: Vec<PatternModifier<'src>>,
}
impl<'src> PatternModifiers<'src> {
pub(crate) fn new(modifiers: Vec<PatternModifier<'src>>) -> Self {
Self { modifiers }
}
#[inline]
pub fn iter(&self) -> PatternModifiersIter<'_> {
PatternModifiersIter { iter: self.modifiers.iter() }
}
#[inline]
pub fn is_empty(&self) -> bool {
self.modifiers.is_empty()
}
#[inline]
pub fn ascii(&self) -> Option<&PatternModifier<'src>> {
self.modifiers
.iter()
.find(|m| matches!(m, PatternModifier::Ascii { .. }))
}
#[inline]
pub fn wide(&self) -> Option<&PatternModifier<'src>> {
self.modifiers
.iter()
.find(|m| matches!(m, PatternModifier::Wide { .. }))
}
#[inline]
pub fn base64(&self) -> Option<&PatternModifier<'src>> {
self.modifiers
.iter()
.find(|m| matches!(m, PatternModifier::Base64 { .. }))
}
#[inline]
pub fn base64wide(&self) -> Option<&PatternModifier<'src>> {
self.modifiers
.iter()
.find(|m| matches!(m, PatternModifier::Base64Wide { .. }))
}
#[inline]
pub fn fullword(&self) -> Option<&PatternModifier<'src>> {
self.modifiers
.iter()
.find(|m| matches!(m, PatternModifier::Fullword { .. }))
}
#[inline]
pub fn nocase(&self) -> Option<&PatternModifier<'src>> {
self.modifiers
.iter()
.find(|m| matches!(m, PatternModifier::Nocase { .. }))
}
#[inline]
pub fn private(&self) -> Option<&PatternModifier<'src>> {
self.modifiers
.iter()
.find(|m| matches!(m, PatternModifier::Private { .. }))
}
#[inline]
pub fn xor(&self) -> Option<&PatternModifier<'src>> {
self.modifiers
.iter()
.find(|m| matches!(m, PatternModifier::Xor { .. }))
}
}
pub struct PatternModifiersIter<'src> {
iter: Iter<'src, PatternModifier<'src>>,
}
impl<'src> Iterator for PatternModifiersIter<'src> {
type Item = &'src PatternModifier<'src>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
}
#[derive(Debug)]
pub enum PatternModifier<'src> {
Ascii { span: Span },
Wide { span: Span },
Nocase { span: Span },
Private { span: Span },
Fullword { span: Span },
Base64 { span: Span, alphabet: Option<LiteralString<'src>> },
Base64Wide { span: Span, alphabet: Option<LiteralString<'src>> },
Xor { span: Span, start: u8, end: u8 },
}
impl PatternModifier<'_> {
pub fn as_text(&self) -> &'static str {
match self {
PatternModifier::Ascii { .. } => "ascii",
PatternModifier::Wide { .. } => "wide",
PatternModifier::Nocase { .. } => "nocase",
PatternModifier::Private { .. } => "private",
PatternModifier::Fullword { .. } => "fullword",
PatternModifier::Base64 { .. } => "base64",
PatternModifier::Base64Wide { .. } => "base64wide",
PatternModifier::Xor { .. } => "xor",
}
}
}
impl Display for PatternModifier<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
PatternModifier::Ascii { .. } => {
write!(f, "ascii")
}
PatternModifier::Wide { .. } => {
write!(f, "wide")
}
PatternModifier::Nocase { .. } => {
write!(f, "nocase")
}
PatternModifier::Private { .. } => {
write!(f, "private")
}
PatternModifier::Fullword { .. } => {
write!(f, "fullword")
}
PatternModifier::Base64 { alphabet, .. } => {
if let Some(alphabet) = alphabet {
write!(f, "base64({})", alphabet.literal)
} else {
write!(f, "base64")
}
}
PatternModifier::Base64Wide { alphabet, .. } => {
if let Some(alphabet) = alphabet {
write!(f, "base64wide({})", alphabet.literal)
} else {
write!(f, "base64wide")
}
}
PatternModifier::Xor { start, end, .. } => {
if *start == 0 && *end == 255 {
write!(f, "xor")
} else if *start == *end {
write!(f, "xor({start})")
} else {
write!(f, "xor({start}-{end})")
}
}
}
}
}
#[derive(Debug)]
pub struct PatternMatch<'src> {
pub identifier: Ident<'src>,
pub anchor: Option<MatchAnchor<'src>>,
}
#[derive(Debug)]
pub enum MatchAnchor<'src> {
At(Box<At<'src>>),
In(Box<In<'src>>),
}
#[derive(Debug)]
pub struct At<'src> {
span: Span,
pub expr: Expr<'src>,
}
#[derive(Debug)]
pub struct Range<'src> {
span: Span,
pub lower_bound: Expr<'src>,
pub upper_bound: Expr<'src>,
}
#[derive(Debug)]
pub struct In<'src> {
span: Span,
pub range: Range<'src>,
}
#[derive(Debug)]
pub struct FuncCall<'src> {
args_span: Span,
pub object: Option<Expr<'src>>,
pub identifier: Ident<'src>,
pub args: Vec<Expr<'src>>,
}
impl FuncCall<'_> {
pub fn args_span(&self) -> Span {
self.args_span.clone()
}
}
#[derive(Debug)]
pub struct Lookup<'src> {
span: Span,
pub primary: Expr<'src>,
pub index: Expr<'src>,
}
#[derive(Debug)]
pub struct LiteralString<'src> {
span: Span,
pub literal: &'src str,
pub value: Cow<'src, BStr>,
}
impl LiteralString<'_> {
pub fn as_str(&self) -> Result<&str, Utf8Error> {
match &self.value {
Cow::Borrowed(s) => Ok(unsafe { s.to_str_unchecked() }),
Cow::Owned(s) => s.to_str(),
}
}
}
#[derive(Debug)]
pub struct LiteralInteger<'src> {
span: Span,
pub literal: &'src str,
pub value: i64,
}
#[derive(Debug)]
pub struct LiteralFloat<'src> {
span: Span,
pub literal: &'src str,
pub value: f64,
}
#[derive(Debug)]
pub struct Regexp<'src> {
span: Span,
pub literal: &'src str,
pub src: &'src str,
pub case_insensitive: bool,
pub dot_matches_new_line: bool,
}
#[derive(Debug)]
pub struct UnaryExpr<'src> {
span: Span,
pub operand: Expr<'src>,
}
#[derive(Debug)]
pub struct BinaryExpr<'src> {
pub lhs: Expr<'src>,
pub rhs: Expr<'src>,
}
#[derive(Debug)]
pub struct NAryExpr<'src> {
pub operands: Vec<Expr<'src>>,
}
impl<'src> NAryExpr<'src> {
#[inline]
pub fn operands(&self) -> Iter<'_, Expr<'src>> {
self.operands.iter()
}
#[inline]
pub fn add(&mut self, expr: Expr<'src>) {
self.operands.push(expr);
}
pub fn first(&self) -> &Expr<'src> {
self.operands
.first()
.expect("expression is expected to have at least one operand")
}
pub fn last(&self) -> &Expr<'src> {
self.operands
.last()
.expect("expression is expected to have at least one operand")
}
#[inline]
pub fn as_slice(&self) -> &[Expr<'src>] {
self.operands.as_slice()
}
}
impl<'src> From<Vec<Expr<'src>>> for NAryExpr<'src> {
fn from(value: Vec<Expr<'src>>) -> Self {
Self { operands: value }
}
}
pub trait WithSpan {
fn span(&self) -> Span;
}
impl WithSpan for LiteralString<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for LiteralInteger<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for LiteralFloat<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for Regexp<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for HexAlternative {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for HexByte {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for HexJump {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for HexToken {
fn span(&self) -> Span {
match self {
HexToken::Byte(byte) => byte.span(),
HexToken::NotByte(byte) => byte.span(),
HexToken::Alternative(alt) => alt.span(),
HexToken::Jump(jump) => jump.span(),
}
}
}
impl WithSpan for HexSubPattern {
fn span(&self) -> Span {
let span = self.0.first().map(|t| t.span()).unwrap_or_default();
if self.0.len() == 1 {
return span;
}
span.combine(&self.0.last().map(|t| t.span()).unwrap_or_default())
}
}
impl WithSpan for Ident<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for IdentWithIndex<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for IdentWithRange<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for Meta<'_> {
fn span(&self) -> Span {
self.identifier.span.combine(&self.value.span())
}
}
impl WithSpan for MetaValue<'_> {
fn span(&self) -> Span {
match self {
MetaValue::Bool((_, span))
| MetaValue::Integer((_, span))
| MetaValue::Float((_, span))
| MetaValue::String((_, span))
| MetaValue::Bytes((_, span)) => span.clone(),
}
}
}
impl WithSpan for ForOf<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for ForIn<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for Of<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for OfItems<'_> {
fn span(&self) -> Span {
match self {
OfItems::PatternSet(patterns) => patterns.span(),
OfItems::BoolExprTuple(tuple) => tuple.span(),
}
}
}
impl WithSpan for With<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for WithDeclaration<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for Iterable<'_> {
fn span(&self) -> Span {
match self {
Iterable::Range(range) => range.span(),
Iterable::ExprTuple(tuple) => tuple.span(),
Iterable::Expr(expr) => expr.span(),
}
}
}
impl WithSpan for Import<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for Include<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for FuncCall<'_> {
fn span(&self) -> Span {
self.identifier.span.combine(&self.args_span)
}
}
impl WithSpan for Pattern<'_> {
fn span(&self) -> Span {
match self {
Pattern::Text(p) => p.span(),
Pattern::Hex(p) => p.span(),
Pattern::Regexp(p) => p.span(),
}
}
}
impl WithSpan for TextPattern<'_> {
fn span(&self) -> Span {
if self.modifiers.is_empty() {
self.identifier.span().combine(&self.text.span)
} else {
self.identifier.span().combine(&self.modifiers.span())
}
}
}
impl WithSpan for HexPattern<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for RegexpPattern<'_> {
fn span(&self) -> Span {
if self.modifiers.is_empty() {
self.identifier.span().combine(&self.regexp.span)
} else {
self.identifier.span().combine(&self.modifiers.span())
}
}
}
impl WithSpan for Range<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for PatternSet<'_> {
fn span(&self) -> Span {
match self {
PatternSet::Them { span } => span.clone(),
PatternSet::Set(items) => {
let span =
items.first().map(|item| item.span()).unwrap_or_default();
if items.len() == 1 {
return span;
}
span.combine(
&items.last().map(|item| item.span()).unwrap_or_default(),
)
}
}
}
}
impl WithSpan for PatternModifier<'_> {
fn span(&self) -> Span {
match self {
PatternModifier::Ascii { span }
| PatternModifier::Wide { span }
| PatternModifier::Nocase { span }
| PatternModifier::Private { span }
| PatternModifier::Fullword { span }
| PatternModifier::Base64 { span, .. }
| PatternModifier::Base64Wide { span, .. }
| PatternModifier::Xor { span, .. } => span.clone(),
}
}
}
impl WithSpan for PatternModifiers<'_> {
fn span(&self) -> Span {
let span = self
.modifiers
.first()
.expect("calling span() on an empty Vec<PatternModifier>")
.span();
if self.modifiers.len() > 1 {
span.combine(&self.modifiers.last().unwrap().span())
} else {
span
}
}
}
impl WithSpan for PatternSetItem<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for Quantifier<'_> {
fn span(&self) -> Span {
match self {
Quantifier::None { span } => span.clone(),
Quantifier::All { span } => span.clone(),
Quantifier::Any { span } => span.clone(),
Quantifier::Percentage(expr) => expr.span(),
Quantifier::Expr(expr) => expr.span(),
}
}
}
impl WithSpan for UnaryExpr<'_> {
fn span(&self) -> Span {
self.span.clone()
}
}
impl WithSpan for BinaryExpr<'_> {
fn span(&self) -> Span {
self.lhs.span().combine(&self.rhs.span())
}
}
impl WithSpan for NAryExpr<'_> {
fn span(&self) -> Span {
self.first().span().combine(&self.last().span())
}
}
impl WithSpan for &Vec<Expr<'_>> {
fn span(&self) -> Span {
let span =
self.first().expect("calling span() on an empty Vec<Expr>").span();
if self.len() > 1 {
span.combine(&self.last().unwrap().span())
} else {
span
}
}
}
impl WithSpan for PatternMatch<'_> {
fn span(&self) -> Span {
let mut span = self.identifier.span();
if let Some(anchor) = &self.anchor {
span = span.combine(&anchor.span())
}
span
}
}
impl WithSpan for MatchAnchor<'_> {
fn span(&self) -> Span {
match self {
MatchAnchor::At(a) => a.span.clone(),
MatchAnchor::In(i) => i.span.clone(),
}
}
}
impl WithSpan for Expr<'_> {
fn span(&self) -> Span {
match self {
Expr::False { span, .. }
| Expr::True { span, .. }
| Expr::Filesize { span, .. }
| Expr::Entrypoint { span, .. } => span.clone(),
Expr::Defined(expr)
| Expr::Not(expr)
| Expr::Minus(expr)
| Expr::BitwiseNot(expr) => expr.span(),
Expr::Shl(expr)
| Expr::Shr(expr)
| Expr::BitwiseAnd(expr)
| Expr::BitwiseOr(expr)
| Expr::BitwiseXor(expr)
| Expr::Eq(expr)
| Expr::Ne(expr)
| Expr::Lt(expr)
| Expr::Gt(expr)
| Expr::Le(expr)
| Expr::Ge(expr)
| Expr::Contains(expr)
| Expr::IContains(expr)
| Expr::StartsWith(expr)
| Expr::IStartsWith(expr)
| Expr::EndsWith(expr)
| Expr::IEndsWith(expr)
| Expr::IEquals(expr)
| Expr::Matches(expr) => expr.span(),
Expr::And(expr)
| Expr::Or(expr)
| Expr::Add(expr)
| Expr::Sub(expr)
| Expr::Mul(expr)
| Expr::Div(expr)
| Expr::Mod(expr)
| Expr::FieldAccess(expr) => expr.span(),
Expr::LiteralString(s) => s.span.clone(),
Expr::LiteralFloat(f) => f.span.clone(),
Expr::LiteralInteger(i) => i.span.clone(),
Expr::Ident(i) => i.span.clone(),
Expr::Regexp(r) => r.span.clone(),
Expr::Lookup(l) => l.span.clone(),
Expr::FuncCall(f) => f.span(),
Expr::PatternMatch(p) => p.span(),
Expr::PatternCount(p) => p.span(),
Expr::PatternLength(p) => p.span(),
Expr::PatternOffset(p) => p.span(),
Expr::ForOf(f) => f.span(),
Expr::ForIn(f) => f.span(),
Expr::Of(o) => o.span(),
Expr::With(w) => w.span(),
}
}
}