From 39b2d61436de28adb93d075ef6224d6a771acc4a Mon Sep 17 00:00:00 2001 From: Matthew Paras <34500476+mattwparas@users.noreply.github.com> Date: Sat, 30 Dec 2023 20:19:22 -0800 Subject: [PATCH] Add custom lints to the language server (#129) * custom lint rules * allow lsp to run even if the lints directory is missing --- .../steel-core/src/parser/tryfrom_visitor.rs | 98 ++++++++++++++++--- crates/steel-language-server/src/backend.rs | 41 +++++--- 2 files changed, 112 insertions(+), 27 deletions(-) diff --git a/crates/steel-core/src/parser/tryfrom_visitor.rs b/crates/steel-core/src/parser/tryfrom_visitor.rs index 89abf07e0..10904919f 100644 --- a/crates/steel-core/src/parser/tryfrom_visitor.rs +++ b/crates/steel-core/src/parser/tryfrom_visitor.rs @@ -1,3 +1,6 @@ +use steel_parser::parser::SyntaxObject; + +use crate::gc::Gc; use crate::values::lists::List; use crate::{parser::ast::ExprKind, rvals::Syntax}; @@ -231,6 +234,14 @@ impl SyntaxObjectFromExprKindRef { } } +fn convert_location(s: &SyntaxObject) -> Result { + let span = s.span; + + let atom = SteelVal::try_from(s.clone())?; + + Ok(Syntax::proto(atom.clone(), atom, span).into()) +} + impl VisitorMut for SyntaxObjectFromExprKindRef { type Output = Result; @@ -242,7 +253,7 @@ impl VisitorMut for SyntaxObjectFromExprKindRef { let span = f.location.span; let expr = [ - SteelVal::try_from(f.location.clone())?, + convert_location(&f.location)?, self.visit(&f.test_expr)?, self.visit(&f.then_expr)?, self.visit(&f.else_expr)?, @@ -260,7 +271,7 @@ impl VisitorMut for SyntaxObjectFromExprKindRef { let span = define.location.span; let expr = [ - SteelVal::try_from(define.location.clone())?, + convert_location(&define.location)?, self.visit(&define.name)?, self.visit(&define.body)?, ]; @@ -283,9 +294,22 @@ impl VisitorMut for SyntaxObjectFromExprKindRef { .map(|x| self.visit(&x)) .collect::>>()?; + let span_vec = args + .iter() + .map(|x| { + if let SteelVal::SyntaxObject(s) = x { + s.syntax_loc() + } else { + unreachable!() + } + }) + .collect::>(); + + let args_span = Span::coalesce_span(&span_vec); + let expr = [ - SteelVal::try_from(lambda_function.location.clone())?, - SteelVal::ListV(args), + convert_location(&lambda_function.location)?, + Syntax::new(SteelVal::ListV(args), args_span).into(), self.visit(&lambda_function.body)?, ]; @@ -297,7 +321,7 @@ impl VisitorMut for SyntaxObjectFromExprKindRef { TryFromExprKindForSteelVal::try_from_expr_kind_quoted(ExprKind::Begin(begin.clone()))?; let span = begin.location.span; - let mut exprs = vec![SteelVal::try_from(begin.location.clone())?]; + let mut exprs = vec![convert_location(&begin.location)?]; for expr in &begin.exprs { exprs.push(self.visit(&expr)?); } @@ -306,10 +330,7 @@ impl VisitorMut for SyntaxObjectFromExprKindRef { fn visit_return(&mut self, r: &steel_parser::ast::Return) -> Self::Output { let span = r.location.span; - let expr = [ - SteelVal::try_from(r.location.clone())?, - self.visit(&r.expr)?, - ]; + let expr = [convert_location(&r.location)?, self.visit(&r.expr)?]; Ok(Syntax::new_with_source(SteelVal::ListV(expr.into_iter().collect()), span).into()) } @@ -395,7 +416,7 @@ impl VisitorMut for SyntaxObjectFromExprKindRef { let span = s.location.span; let expr = [ - SteelVal::try_from(s.location.clone())?, + convert_location(&s.location)?, self.visit(&s.variable)?, self.visit(&s.expr)?, ]; @@ -406,8 +427,61 @@ impl VisitorMut for SyntaxObjectFromExprKindRef { stop!(Generic => "internal compiler error - could not translate require to steel value") } - fn visit_let(&mut self, _l: &steel_parser::ast::Let) -> Self::Output { - todo!() + fn visit_let(&mut self, l: &steel_parser::ast::Let) -> Self::Output { + let raw: SteelVal = TryFromExprKindForSteelVal::try_from_expr_kind_quoted(ExprKind::Let( + Box::new(l.clone()), + ))?; + + let span = l.location.span; + + let items = l + .bindings + .iter() + .map(|(x, y)| { + let items = vec![self.visit(x)?, self.visit(y)?]; + + let span_vec = items + .iter() + .map(|x| { + if let SteelVal::SyntaxObject(s) = x { + s.syntax_loc() + } else { + unreachable!() + } + }) + .collect::>(); + + let items_span = Span::coalesce_span(&span_vec); + + Ok(SteelVal::SyntaxObject(Gc::new(Syntax::new( + SteelVal::ListV(items.into()), + items_span, + )))) + }) + .collect::, SteelErr>>()?; + // .into(), + + let span_vec = items + .iter() + .map(|x| { + if let SteelVal::SyntaxObject(s) = x { + s.syntax_loc() + } else { + unreachable!() + } + }) + .collect::>(); + + let items_span = Span::coalesce_span(&span_vec); + + let expr = [ + convert_location(&l.location)?, + // Bindings + Syntax::new(items.into(), items_span).into(), + self.visit(&l.body_expr)?, + ]; + + Ok(Syntax::proto(raw, SteelVal::ListV(expr.into_iter().collect()), span).into()) } } diff --git a/crates/steel-language-server/src/backend.rs b/crates/steel-language-server/src/backend.rs index aefb4a866..01402bd52 100644 --- a/crates/steel-language-server/src/backend.rs +++ b/crates/steel-language-server/src/backend.rs @@ -772,10 +772,17 @@ impl Backend { free_identifiers_and_unused.append(&mut static_arity_checking); + let now = std::time::Instant::now(); + // TODO: Enable this once the syntax object let conversion is implemented - // let mut user_defined_lints = - // LINT_ENGINE.with_borrow_mut(|x| x.diagnostics(&rope, &analysis.exprs)); - // free_identifiers_and_unused.append(&mut user_defined_lints); + let mut user_defined_lints = + LINT_ENGINE.with_borrow_mut(|x| x.diagnostics(&rope, &analysis.exprs)); + + log::debug!("Lints found: {:#?}", user_defined_lints); + + free_identifiers_and_unused.append(&mut user_defined_lints); + + log::debug!("User defined lints time taken: {:?}", now.elapsed()); // All the diagnostics total free_identifiers_and_unused @@ -858,7 +865,7 @@ impl steel::steel_vm::engine::ModuleResolver for ExternalModuleResolver { thread_local! { pub static ENGINE: RefCell = RefCell::new(Engine::new()); - // pub static LINT_ENGINE: RefCell = RefCell::new(configure_lints().unwrap()); + pub static LINT_ENGINE: RefCell = RefCell::new(configure_lints().unwrap()); pub static DIAGNOSTICS: RefCell> = RefCell::new(Vec::new()); } @@ -880,9 +887,11 @@ impl UserDefinedLintEngine { for lint in lints.iter() { for object in &syntax_objects { if let Ok(o) = object.clone() { - self.engine - .call_function_by_name_with_args(lint, vec![o]) - .ok(); + log::debug!("calling: {} with {}", lint, o); + + let res = self.engine.call_function_by_name_with_args(lint, vec![o]); + + log::debug!("{:?}", res); } } } @@ -916,6 +925,7 @@ fn configure_lints() -> std::result::Result std::result::Result