aboutsummaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/analysis.rs108
-rw-r--r--src/eval/builtins.rs45
2 files changed, 126 insertions, 27 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}
diff --git a/src/eval/builtins.rs b/src/eval/builtins.rs
index 7d10a86..c91f7ba 100644
--- a/src/eval/builtins.rs
+++ b/src/eval/builtins.rs
@@ -29,6 +29,8 @@ builtins! {
29 // string 29 // string
30 isupper, 30 isupper,
31 islower, 31 islower,
32 toupper,
33 tolower,
32 substr, 34 substr,
33 35
34 // node 36 // node
@@ -78,6 +80,22 @@ fn islower(ctx: &mut Context, args: &[ast::Expr]) -> Result {
78 .into()) 80 .into())
79} 81}
80 82
83fn toupper(ctx: &mut Context, args: &[ast::Expr]) -> Result {
84 Ok(ctx
85 .eval_expr(&get_args::<1>(args)?[0])?
86 .as_str()?
87 .to_uppercase()
88 .into())
89}
90
91fn tolower(ctx: &mut Context, args: &[ast::Expr]) -> Result {
92 Ok(ctx
93 .eval_expr(&get_args::<1>(args)?[0])?
94 .as_str()?
95 .to_lowercase()
96 .into())
97}
98
81fn substr(ctx: &mut Context, args: &[ast::Expr]) -> Result { 99fn substr(ctx: &mut Context, args: &[ast::Expr]) -> Result {
82 if let Ok([string, start, end]) = get_args::<3>(args) { 100 if let Ok([string, start, end]) = get_args::<3>(args) {
83 let v = ctx.eval_expr(string)?; 101 let v = ctx.eval_expr(string)?;
@@ -217,30 +235,3 @@ fn get_args<const N: usize>(args: &[ast::Expr]) -> std::result::Result<&[ast::Ex
217 got: args.len(), 235 got: args.len(),
218 }) 236 })
219} 237}
220
221#[cfg(test)]
222mod test {
223 use super::*;
224 use crate::{ast::*, eval::*};
225
226 #[test]
227 fn test_ts_builtins() {
228 let language = tree_sitter_python::language();
229 let mut ctx = Context::new(language).with_program(Program::new());
230
231 assert_eq!(
232 ctx.eval_block(&Block {
233 body: vec![Statement::decl(Type::List, "a", Expr::list([Expr::int(5)]),)]
234 }),
235 Ok(Value::Unit)
236 );
237 assert_eq!(
238 ctx.lookup(&String::from("a")).unwrap().clone(),
239 Variable {
240 ty: Type::List,
241 name: "a".to_owned(),
242 value: vec![5usize.into()].into(),
243 }
244 );
245 }
246}