1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
macro_rules! explain_lint {
($(#[doc = $doc:expr])+ $code:ident: $linter:ident) => {
use crate::diagnostics::DiagnosticRecord;
$(#[doc = $doc])+
impl<'a> DiagnosticRecord for $linter<'a> {
const CODE: &'static str = stringify!($code);
const EXPLANATION: &'static str = concat!($($doc, "\n"),+);
}
};
}
mod stmt;
use stmt::*;
mod expr_pat;
use expr_pat::*;
use crate::diagnostics::{Diagnostic, DiagnosticRecord, DiagnosticRegistry};
use crate::grammar::{Grammar, RcExprPat, StmtList};
pub trait LintRule<'a, G>
where
Self: DiagnosticRecord,
G: Grammar,
{
fn lint(grammar: &G, source: &'a str) -> Vec<Diagnostic>;
}
pub struct LintConfig {
stmt_linters: Vec<StmtLintRule>,
expr_pat_linters: Vec<ExprPatLintRule>,
}
impl Default for LintConfig {
fn default() -> Self {
Self {
stmt_linters: vec![
StmtLintRule::UnarySeriesLinter,
StmtLintRule::RedundantNestingLinter,
StmtLintRule::HomogenousAssignmentLinter,
],
expr_pat_linters: vec![ExprPatLintRule::SimilarNamesLinter],
}
}
}
impl DiagnosticRegistry for LintConfig {
fn codes_with_explanations() -> Vec<(&'static str, &'static str)> {
let mut vec = Vec::new();
vec.extend(StmtLintRule::all_explanations());
vec.extend(ExprPatLintRule::all_explanations());
vec
}
}
pub fn lint_stmt(stmt_list: &StmtList, source: &str) -> Vec<Diagnostic> {
let config = LintConfig::default();
let mut diags = vec![];
for linter in config.stmt_linters.iter() {
diags.extend(linter.lint(stmt_list, source))
}
diags
}
pub fn lint_expr_pat(expr_pat: &RcExprPat, source: &str) -> Vec<Diagnostic> {
let config = LintConfig::default();
let mut diags = vec![];
for linter in config.expr_pat_linters {
diags.extend(linter.lint(expr_pat, source))
}
diags
}