diff options
author | Akshay <[email protected]> | 2024-10-12 14:33:22 +0100 |
---|---|---|
committer | Akshay <[email protected]> | 2024-10-12 14:33:22 +0100 |
commit | bdbb1b33fdac8491bc9a517be3807d97e17d69c9 (patch) | |
tree | dca73ccae376a46dff8bec55903398e8d0a00ed8 /src/eval/analysis.rs | |
parent | 63c606d17095e336ee0deeedb30f94a490ec4059 (diff) |
trace errors in tests, add warnings to tbsp
Diffstat (limited to 'src/eval/analysis.rs')
-rw-r--r-- | src/eval/analysis.rs | 76 |
1 files changed, 65 insertions, 11 deletions
diff --git a/src/eval/analysis.rs b/src/eval/analysis.rs index b3a0083..d5a7165 100644 --- a/src/eval/analysis.rs +++ b/src/eval/analysis.rs | |||
@@ -6,10 +6,17 @@ pub struct Analysis { | |||
6 | } | 6 | } |
7 | 7 | ||
8 | impl Analysis { | 8 | impl Analysis { |
9 | pub fn print(&self) { | 9 | pub fn contains_error(&self) -> bool { |
10 | self.diagnostics.iter().any(|d| d.level == Level::Error) | ||
11 | } | ||
12 | } | ||
13 | |||
14 | impl std::fmt::Display for Analysis { | ||
15 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
10 | for Diagnostic { level, kind } in &self.diagnostics { | 16 | for Diagnostic { level, kind } in &self.diagnostics { |
11 | eprintln!("{level} {kind}"); | 17 | writeln!(f, "{level} {kind}")?; |
12 | } | 18 | } |
19 | Ok(()) | ||
13 | } | 20 | } |
14 | } | 21 | } |
15 | 22 | ||
@@ -36,16 +43,20 @@ impl std::fmt::Display for Level { | |||
36 | 43 | ||
37 | #[derive(Debug, PartialEq, Eq)] | 44 | #[derive(Debug, PartialEq, Eq)] |
38 | pub enum Kind { | 45 | pub enum Kind { |
39 | Pattern { | 46 | InvalidPattern { |
40 | invalid_node_kind: String, | 47 | invalid_node_kind: String, |
41 | full_pattern: ast::Pattern, | 48 | full_pattern: ast::Pattern, |
42 | }, | 49 | }, |
50 | SimplifiablePattern { | ||
51 | pattern: ast::TreePattern, | ||
52 | simplified: ast::TreePattern, | ||
53 | }, | ||
43 | } | 54 | } |
44 | 55 | ||
45 | impl std::fmt::Display for Kind { | 56 | impl std::fmt::Display for Kind { |
46 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | 57 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
47 | match self { | 58 | match self { |
48 | Self::Pattern { | 59 | Self::InvalidPattern { |
49 | invalid_node_kind, | 60 | invalid_node_kind, |
50 | full_pattern, | 61 | full_pattern, |
51 | } => { | 62 | } => { |
@@ -54,12 +65,21 @@ impl std::fmt::Display for Kind { | |||
54 | "invalid node kind `{invalid_node_kind}` in pattern `{full_pattern}`" | 65 | "invalid node kind `{invalid_node_kind}` in pattern `{full_pattern}`" |
55 | ) | 66 | ) |
56 | } | 67 | } |
68 | Self::SimplifiablePattern { | ||
69 | pattern, | ||
70 | simplified, | ||
71 | } => { | ||
72 | write!( | ||
73 | f, | ||
74 | "the pattern `{pattern}` can be reduced to just `{simplified}`" | ||
75 | ) | ||
76 | } | ||
57 | } | 77 | } |
58 | } | 78 | } |
59 | } | 79 | } |
60 | 80 | ||
61 | pub fn run(ctx: &super::Context) -> Analysis { | 81 | pub fn run(ctx: &super::Context) -> Analysis { |
62 | [validate_patterns(ctx)] | 82 | [validate_patterns(ctx), redundant_list_pattern(ctx)] |
63 | .into_iter() | 83 | .into_iter() |
64 | .flatten() | 84 | .flatten() |
65 | .collect::<Vec<_>>() | 85 | .collect::<Vec<_>>() |
@@ -67,11 +87,9 @@ pub fn run(ctx: &super::Context) -> Analysis { | |||
67 | } | 87 | } |
68 | 88 | ||
69 | fn validate_patterns(ctx: &super::Context) -> Vec<Diagnostic> { | 89 | fn validate_patterns(ctx: &super::Context) -> Vec<Diagnostic> { |
70 | fn validate_pattern( | 90 | fn check(pattern: &ast::TreePattern, language: &tree_sitter::Language) -> Option<String> { |
71 | pattern: &ast::TreePattern, | ||
72 | language: &tree_sitter::Language, | ||
73 | ) -> Option<String> { | ||
74 | match pattern { | 91 | match pattern { |
92 | // base case | ||
75 | ast::TreePattern::Atom(a) => { | 93 | ast::TreePattern::Atom(a) => { |
76 | if language.id_for_node_kind(a, true) == 0 { | 94 | if language.id_for_node_kind(a, true) == 0 { |
77 | Some(a.to_owned()) | 95 | Some(a.to_owned()) |
@@ -79,9 +97,10 @@ fn validate_patterns(ctx: &super::Context) -> Vec<Diagnostic> { | |||
79 | None | 97 | None |
80 | } | 98 | } |
81 | } | 99 | } |
100 | // recursive case | ||
82 | ast::TreePattern::List(items) => { | 101 | ast::TreePattern::List(items) => { |
83 | for item in items { | 102 | for item in items { |
84 | validate_pattern(item, language)?; | 103 | check(item, language)?; |
85 | } | 104 | } |
86 | None | 105 | None |
87 | } | 106 | } |
@@ -94,7 +113,7 @@ fn validate_patterns(ctx: &super::Context) -> Vec<Diagnostic> { | |||
94 | .flat_map(|s| match &s.pattern { | 113 | .flat_map(|s| match &s.pattern { |
95 | ast::Pattern::Begin | ast::Pattern::End => None, | 114 | ast::Pattern::Begin | ast::Pattern::End => None, |
96 | ast::Pattern::Tree { matcher, .. } => { | 115 | ast::Pattern::Tree { matcher, .. } => { |
97 | validate_pattern(matcher, &ctx.language).map(|invalid_node_kind| Kind::Pattern { | 116 | check(matcher, &ctx.language).map(|invalid_node_kind| Kind::InvalidPattern { |
98 | invalid_node_kind, | 117 | invalid_node_kind, |
99 | full_pattern: s.pattern.clone(), | 118 | full_pattern: s.pattern.clone(), |
100 | }) | 119 | }) |
@@ -106,3 +125,38 @@ fn validate_patterns(ctx: &super::Context) -> Vec<Diagnostic> { | |||
106 | }) | 125 | }) |
107 | .collect() | 126 | .collect() |
108 | } | 127 | } |
128 | |||
129 | fn redundant_list_pattern(ctx: &super::Context) -> Vec<Diagnostic> { | ||
130 | fn simplify(pattern: &ast::TreePattern) -> ast::TreePattern { | ||
131 | match pattern { | ||
132 | ast::TreePattern::Atom(a) => ast::TreePattern::Atom(a.to_owned()), | ||
133 | ast::TreePattern::List(l) => match l.as_slice() { | ||
134 | [a] => simplify(a), | ||
135 | items => ast::TreePattern::List(items.iter().map(simplify).collect::<Vec<_>>()), | ||
136 | }, | ||
137 | } | ||
138 | } | ||
139 | |||
140 | ctx.program | ||
141 | .stanzas | ||
142 | .iter() | ||
143 | .flat_map(|s| match &s.pattern { | ||
144 | ast::Pattern::Begin | ast::Pattern::End => None, | ||
145 | ast::Pattern::Tree { matcher, .. } => { | ||
146 | let simplified = simplify(matcher); | ||
147 | if &simplified != matcher { | ||
148 | Some(Kind::SimplifiablePattern { | ||
149 | pattern: matcher.clone(), | ||
150 | simplified, | ||
151 | }) | ||
152 | } else { | ||
153 | None | ||
154 | } | ||
155 | } | ||
156 | }) | ||
157 | .map(|kind| Diagnostic { | ||
158 | level: Level::Warning, | ||
159 | kind, | ||
160 | }) | ||
161 | .collect() | ||
162 | } | ||