use crate::config::ConfigOption;
use crate::linter::{SyntaxRule, SyntaxRuleResult};
use regex::Regex;
use sv_parser::{NodeEvent, RefNode, SyntaxTree};
#[derive(Default)]
pub struct StyleOperatorArithmetic {
re_split: Option<Regex>,
re_op: Option<Regex>,
re_succ: Option<Regex>,
}
impl SyntaxRule for StyleOperatorArithmetic {
fn check(
&mut self,
syntax_tree: &SyntaxTree,
event: &NodeEvent,
_option: &ConfigOption,
) -> SyntaxRuleResult {
if self.re_split.is_none() {
self.re_split = Some(Regex::new(r"(?P<op>\S+)(?P<succ>(?s:.)*)").unwrap());
}
if self.re_op.is_none() {
let operators =
[ "\\+" , "-"
, "\\*"
, "/"
, "%"
, "\\*\\*"
].join("|"); self.re_op = Some(Regex::new(format!("^({})$", operators).as_str()).unwrap());
}
if self.re_succ.is_none() {
self.re_succ = Some(Regex::new(r"^($|[\n\v\f\r]| /| $)").unwrap());
}
let node = match event {
NodeEvent::Enter(x) => x,
NodeEvent::Leave(_) => {
return SyntaxRuleResult::Pass;
}
};
match node {
RefNode::BinaryOperator(x) => {
let re_split = self.re_split.as_ref().unwrap();
let re_op = self.re_op.as_ref().unwrap();
let t = syntax_tree.get_str(*x).unwrap();
let caps = re_split.captures(&t).unwrap();
if re_op.is_match(&caps[1]) {
let re_succ = self.re_succ.as_ref().unwrap();
if re_succ.is_match(&caps[2]) {
SyntaxRuleResult::Pass
} else {
SyntaxRuleResult::Fail
}
} else {
SyntaxRuleResult::Pass
}
}
_ => SyntaxRuleResult::Pass,
}
}
fn name(&self) -> String {
String::from("style_operator_arithmetic")
}
fn hint(&self, _option: &ConfigOption) -> String {
String::from("Follow operator with a symbol, identifier, newline, or exactly 1 space.")
}
fn reason(&self) -> String {
String::from("Consistent use of whitespace enhances readability by reducing visual noise.")
}
}