Lints and suggestions for the Nix programming language
at main 94 lines 2.5 kB view raw
1use std::{fmt::Write, iter::IntoIterator}; 2 3use rnix::{ 4 Root, SyntaxNode, 5 ast::{self, AstNode}, 6}; 7use rowan::ast::AstNode as _; 8 9fn ast_from_text<N: AstNode>(text: &str) -> N { 10 let parse = Root::parse(text).ok(); 11 12 let Ok(parse) = parse else { 13 panic!("Failed to parse `{text:?}`") 14 }; 15 16 let Some(node) = parse.syntax().descendants().find_map(N::cast) else { 17 panic!( 18 "Failed to make ast node `{}` from text `{}`", 19 std::any::type_name::<N>(), 20 text 21 ); 22 }; 23 24 node 25} 26 27pub fn parenthesize(node: &SyntaxNode) -> ast::Paren { 28 ast_from_text(&format!("({node})")) 29} 30 31pub fn quote(node: &SyntaxNode) -> ast::Str { 32 ast_from_text(&format!("\"{node}\"")) 33} 34 35pub fn unary_not(node: &SyntaxNode) -> ast::UnaryOp { 36 ast_from_text(&format!("!{node}")) 37} 38 39pub fn inherit_stmt<'a>(nodes: impl IntoIterator<Item = &'a ast::Ident>) -> ast::Inherit { 40 let inherited_idents = nodes 41 .into_iter() 42 .map(std::string::ToString::to_string) 43 .collect::<Vec<_>>() 44 .join(" "); 45 ast_from_text(&format!("{{ inherit {inherited_idents}; }}")) 46} 47 48pub fn inherit_from_stmt<'a>( 49 from: &SyntaxNode, 50 nodes: impl IntoIterator<Item = &'a ast::Ident>, 51) -> ast::Inherit { 52 let inherited_idents = nodes 53 .into_iter() 54 .map(std::string::ToString::to_string) 55 .collect::<Vec<_>>() 56 .join(" "); 57 ast_from_text(&format!("{{ inherit ({from}) {inherited_idents}; }}")) 58} 59 60pub fn attrset( 61 inherits: impl IntoIterator<Item = ast::Inherit>, 62 entries: impl IntoIterator<Item = ast::Entry>, 63 recursive: bool, 64) -> ast::AttrSet { 65 let mut buffer = String::new(); 66 67 writeln!(buffer, "{}{{", if recursive { "rec " } else { "" }).unwrap(); 68 for inherit in inherits { 69 writeln!(buffer, " {inherit}").unwrap(); 70 } 71 for entry in entries { 72 writeln!(buffer, " {entry}").unwrap(); 73 } 74 write!(buffer, "}}").unwrap(); 75 76 ast_from_text(&buffer) 77} 78 79pub fn select(set: &SyntaxNode, index: &SyntaxNode) -> ast::Select { 80 ast_from_text(&format!("{set}.{index}")) 81} 82 83pub fn ident(text: &str) -> ast::Ident { 84 ast_from_text(text) 85} 86 87// LATER: make `op` strongly typed here 88pub fn binary(lhs: &SyntaxNode, op: &str, rhs: &SyntaxNode) -> ast::BinOp { 89 ast_from_text(&format!("{lhs} {op} {rhs}")) 90} 91 92pub fn or_default(set: &SyntaxNode, index: &SyntaxNode, default: &SyntaxNode) -> ast::Select { 93 ast_from_text(&format!("{set}.{index} or {default}")) 94}