-
-
Notifications
You must be signed in to change notification settings - Fork 45
/
list-fns.rs
95 lines (89 loc) · 3.19 KB
/
list-fns.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use std::{env, error::Error, fs};
use rnix::{
ast::{self, AstToken, HasEntry},
match_ast, NodeOrToken, SyntaxNode,
};
use rowan::ast::AstNode;
macro_rules! single_match {
($expression:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? => $captured:expr) => {
match $expression {
$( $pattern )|+ $( if $guard )? => Some($captured),
_ => None
}
};
}
fn main() -> Result<(), Box<dyn Error>> {
let file = match env::args().nth(1) {
Some(file) => file,
None => {
eprintln!("Usage: list-fns <file>");
return Ok(());
}
};
let content = fs::read_to_string(&file)?;
let ast = rnix::Root::parse(&content).ok()?;
let expr = ast.expr().unwrap();
let set = match expr {
ast::Expr::AttrSet(set) => set,
_ => return Err("root isn't a set".into()),
};
for entry in set.entries() {
if let ast::Entry::AttrpathValue(attrpath_value) = entry {
if let Some(ast::Expr::Lambda(lambda)) = attrpath_value.value() {
let attrpath = attrpath_value.attrpath().unwrap();
let ident = attrpath.attrs().last().and_then(|attr| match attr {
ast::Attr::Ident(ident) => Some(ident),
_ => None,
});
let s = ident.as_ref().map_or_else(
|| "error".to_string(),
|ident| ident.ident_token().unwrap().text().to_string(),
);
println!("Function name: {}", s);
{
let comments = comments_before(attrpath_value.syntax());
if !comments.is_empty() {
println!("--> Doc: {comments}");
}
}
let mut value = Some(lambda);
while let Some(lambda) = value {
let s = lambda
.param()
.as_ref()
.map_or_else(|| "error".to_string(), |param| param.to_string());
println!("-> Param: {}", s);
{
let comments = comments_before(lambda.syntax());
if !comments.is_empty() {
println!("--> Doc: {comments}");
}
}
value =
single_match!(lambda.body().unwrap(), ast::Expr::Lambda(lambda) => lambda);
}
println!();
}
}
}
Ok(())
}
fn comments_before(node: &SyntaxNode) -> String {
node.siblings_with_tokens(rowan::Direction::Prev)
// rowan always returns the first node for some reason
.skip(1)
.map_while(|element| match element {
NodeOrToken::Token(token) => match_ast! {
match token {
ast::Comment(it) => Some(Some(it)),
ast::Whitespace(_) => Some(None),
_ => None,
}
},
_ => None,
})
.flatten()
.map(|s| s.text().trim().to_string())
.collect::<Vec<_>>()
.join("\n ")
}