aboutsummaryrefslogtreecommitdiff
path: root/src/eval/analysis.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval/analysis.rs')
-rw-r--r--src/eval/analysis.rs108
1 files changed, 108 insertions, 0 deletions
diff --git a/src/eval/analysis.rs b/src/eval/analysis.rs
new file mode 100644
index 0000000..b3a0083
--- /dev/null
+++ b/src/eval/analysis.rs
@@ -0,0 +1,108 @@
1use crate::{ast, Wrap};
2
3#[derive(Debug, PartialEq, Eq)]
4pub struct Analysis {
5 diagnostics: Vec<Diagnostic>,
6}
7
8impl Analysis {
9 pub fn print(&self) {
10 for Diagnostic { level, kind } in &self.diagnostics {
11 eprintln!("{level} {kind}");
12 }
13 }
14}
15
16#[derive(Debug, PartialEq, Eq)]
17pub struct Diagnostic {
18 level: Level,
19 kind: Kind,
20}
21
22#[derive(Debug, PartialEq, Eq)]
23pub enum Level {
24 Warning,
25 Error,
26}
27
28impl std::fmt::Display for Level {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 match self {
31 Level::Warning => write!(f, "[warning]"),
32 Level::Error => write!(f, "[error]"),
33 }
34 }
35}
36
37#[derive(Debug, PartialEq, Eq)]
38pub enum Kind {
39 Pattern {
40 invalid_node_kind: String,
41 full_pattern: ast::Pattern,
42 },
43}
44
45impl std::fmt::Display for Kind {
46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47 match self {
48 Self::Pattern {
49 invalid_node_kind,
50 full_pattern,
51 } => {
52 write!(
53 f,
54 "invalid node kind `{invalid_node_kind}` in pattern `{full_pattern}`"
55 )
56 }
57 }
58 }
59}
60
61pub fn run(ctx: &super::Context) -> Analysis {
62 [validate_patterns(ctx)]
63 .into_iter()
64 .flatten()
65 .collect::<Vec<_>>()
66 .wrap(|diagnostics| Analysis { diagnostics })
67}
68
69fn validate_patterns(ctx: &super::Context) -> Vec<Diagnostic> {
70 fn validate_pattern(
71 pattern: &ast::TreePattern,
72 language: &tree_sitter::Language,
73 ) -> Option<String> {
74 match pattern {
75 ast::TreePattern::Atom(a) => {
76 if language.id_for_node_kind(a, true) == 0 {
77 Some(a.to_owned())
78 } else {
79 None
80 }
81 }
82 ast::TreePattern::List(items) => {
83 for item in items {
84 validate_pattern(item, language)?;
85 }
86 None
87 }
88 }
89 }
90
91 ctx.program
92 .stanzas
93 .iter()
94 .flat_map(|s| match &s.pattern {
95 ast::Pattern::Begin | ast::Pattern::End => None,
96 ast::Pattern::Tree { matcher, .. } => {
97 validate_pattern(matcher, &ctx.language).map(|invalid_node_kind| Kind::Pattern {
98 invalid_node_kind,
99 full_pattern: s.pattern.clone(),
100 })
101 }
102 })
103 .map(|kind| Diagnostic {
104 level: Level::Error,
105 kind,
106 })
107 .collect()
108}