mod context;
mod diagnostics;
mod rules;
#[cfg(test)]
mod tests;
pub use context::LintContext;
pub use diagnostics::{Diagnostic, FuseBlown};
pub use rules::{
BypassCapRule, GhostNetRule, MalformedElementRule, PinMuxRule, TraceClearanceRule,
UnconnectedNetRule,
};
use crate::netlist::Netlist;
use crate::parser::Circuit;
pub trait Rule {
fn name(&self) -> &'static str;
fn check(&self, ctx: &LintContext<'_>) -> Vec<Diagnostic>;
}
pub struct Linter {
rules: Vec<Box<dyn Rule>>,
}
impl Linter {
pub fn new() -> Self {
Self { rules: Vec::new() }
}
pub fn with_rule(mut self, rule: impl Rule + 'static) -> Self {
self.rules.push(Box::new(rule));
self
}
pub fn run(&self, circuit: &Circuit) -> Vec<Diagnostic> {
let netlist = Netlist::from_circuit(circuit);
let ctx = LintContext::new(circuit, &netlist);
self.run_with_context(&ctx)
}
pub fn run_with_context(&self, ctx: &LintContext<'_>) -> Vec<Diagnostic> {
self.rules.iter().flat_map(|rule| rule.check(ctx)).collect()
}
}
impl Default for Linter {
fn default() -> Self {
Self::new()
.with_rule(UnconnectedNetRule)
.with_rule(MalformedElementRule)
.with_rule(GhostNetRule)
.with_rule(PinMuxRule)
.with_rule(BypassCapRule)
.with_rule(TraceClearanceRule)
}
}