From 63c606d17095e336ee0deeedb30f94a490ec4059 Mon Sep 17 00:00:00 2001 From: Akshay Date: Fri, 11 Oct 2024 08:25:31 +0530 Subject: add analysis phase --- src/eval/analysis.rs | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/eval/builtins.rs | 45 +++++++++------------ 2 files changed, 126 insertions(+), 27 deletions(-) create mode 100644 src/eval/analysis.rs (limited to 'src/eval') 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 @@ +use crate::{ast, Wrap}; + +#[derive(Debug, PartialEq, Eq)] +pub struct Analysis { + diagnostics: Vec, +} + +impl Analysis { + pub fn print(&self) { + for Diagnostic { level, kind } in &self.diagnostics { + eprintln!("{level} {kind}"); + } + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct Diagnostic { + level: Level, + kind: Kind, +} + +#[derive(Debug, PartialEq, Eq)] +pub enum Level { + Warning, + Error, +} + +impl std::fmt::Display for Level { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Level::Warning => write!(f, "[warning]"), + Level::Error => write!(f, "[error]"), + } + } +} + +#[derive(Debug, PartialEq, Eq)] +pub enum Kind { + Pattern { + invalid_node_kind: String, + full_pattern: ast::Pattern, + }, +} + +impl std::fmt::Display for Kind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Pattern { + invalid_node_kind, + full_pattern, + } => { + write!( + f, + "invalid node kind `{invalid_node_kind}` in pattern `{full_pattern}`" + ) + } + } + } +} + +pub fn run(ctx: &super::Context) -> Analysis { + [validate_patterns(ctx)] + .into_iter() + .flatten() + .collect::>() + .wrap(|diagnostics| Analysis { diagnostics }) +} + +fn validate_patterns(ctx: &super::Context) -> Vec { + fn validate_pattern( + pattern: &ast::TreePattern, + language: &tree_sitter::Language, + ) -> Option { + match pattern { + ast::TreePattern::Atom(a) => { + if language.id_for_node_kind(a, true) == 0 { + Some(a.to_owned()) + } else { + None + } + } + ast::TreePattern::List(items) => { + for item in items { + validate_pattern(item, language)?; + } + None + } + } + } + + ctx.program + .stanzas + .iter() + .flat_map(|s| match &s.pattern { + ast::Pattern::Begin | ast::Pattern::End => None, + ast::Pattern::Tree { matcher, .. } => { + validate_pattern(matcher, &ctx.language).map(|invalid_node_kind| Kind::Pattern { + invalid_node_kind, + full_pattern: s.pattern.clone(), + }) + } + }) + .map(|kind| Diagnostic { + level: Level::Error, + kind, + }) + .collect() +} 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! { // string isupper, islower, + toupper, + tolower, substr, // node @@ -78,6 +80,22 @@ fn islower(ctx: &mut Context, args: &[ast::Expr]) -> Result { .into()) } +fn toupper(ctx: &mut Context, args: &[ast::Expr]) -> Result { + Ok(ctx + .eval_expr(&get_args::<1>(args)?[0])? + .as_str()? + .to_uppercase() + .into()) +} + +fn tolower(ctx: &mut Context, args: &[ast::Expr]) -> Result { + Ok(ctx + .eval_expr(&get_args::<1>(args)?[0])? + .as_str()? + .to_lowercase() + .into()) +} + fn substr(ctx: &mut Context, args: &[ast::Expr]) -> Result { if let Ok([string, start, end]) = get_args::<3>(args) { let v = ctx.eval_expr(string)?; @@ -217,30 +235,3 @@ fn get_args(args: &[ast::Expr]) -> std::result::Result<&[ast::Ex got: args.len(), }) } - -#[cfg(test)] -mod test { - use super::*; - use crate::{ast::*, eval::*}; - - #[test] - fn test_ts_builtins() { - let language = tree_sitter_python::language(); - let mut ctx = Context::new(language).with_program(Program::new()); - - assert_eq!( - ctx.eval_block(&Block { - body: vec![Statement::decl(Type::List, "a", Expr::list([Expr::int(5)]),)] - }), - Ok(Value::Unit) - ); - assert_eq!( - ctx.lookup(&String::from("a")).unwrap().clone(), - Variable { - ty: Type::List, - name: "a".to_owned(), - value: vec![5usize.into()].into(), - } - ); - } -} -- cgit v1.2.3