-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnotes.txt
107 lines (100 loc) · 3.22 KB
/
notes.txt
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
96
97
98
99
100
101
102
103
104
105
106
107
struct Args {
vars: HashSet<Ident>,
}
impl Args {
fn should_print_expr(&self, e: &Expr) -> bool {
if let Expr::Path(ref e) = e {
if e.path.leading_colon.is_some() {
false
} else if e.path.segments.len() != 1 {
false
} else {
let first = e.path.segments.first().unwrap();
self.vars.contains(&first.ident) && first.arguments.is_empty()
}
} else {
false
}
}
fn should_print_pat(&self, p: &Pat) -> bool {
if let Pat::Ident(ref p) = p {
self.vars.contains(&p.ident)
} else {
false
}
}
fn assign_and_print(&mut self, left: Expr, op: &dyn ToTokens, right: Expr) -> Expr {
let right = fold::fold_expr(self, right);
parse_quote!({
println!(concat!(stringify!(#left), " = {:?}"), #left);
})
}
fn let_and_print(&mut self, local: Local) -> Stmt {
let Local { pat, init, .. } = local;
let init = self.fold_expr(*init.unwrap().1);
// get the variable name of assigned variable
let ident = match pat {
Pat::Ident(ref p) => &p.ident,
_ => unreachable!(),
};
// new sub tree
parse_quote! {
let #pat = {
#[allow(unused_mut)]
let #pat = #init;
println!(concat!(stringify!(#ident), " = {:?}"), #ident);
#ident
};
}
}
}
impl Fold for Args {
fn fold_expr(&mut self, e: Expr) -> Expr {
match e {
Expr::Assign(e) => {
if self.should_print_expr(&e.left) {
self.assign_and_print(*e.left, &e.eq_token, *e.right)
} else {
Expr::Assign(fold::fold_expr_assign(self, e))
}
}
Expr::AssignOp(e) => {
if self.should_print_expr(&e.left) {
self.assign_and_print(*e.left, &e.op, *e.right)
} else {
Expr::AssignOp(fold::fold_expr_assign_op(self, e))
}
}
_ => fold::fold_expr(self, e),
}
}
fn fold_stmt(&mut self, s: Stmt) -> Stmt {
match s {
Stmt::Local(s) => {
if s.init.is_some() && self.should_print_pat(&s.pat) {
self.let_and_print( s)
} else {
Stmt::Local(fold::fold_local(self, s))
}
}
_ => fold::fold_stmt(self, s)
}
}
}
impl Parse for Args {
fn parse(input: ParseStream) -> Result<Self> {
// parses a,b,c, or a,b,c where a,b and c are Indent
let vars = Punctuated::<Ident, Token![,]>::parse_terminated(input)?;
Ok(Args {
vars: vars.into_iter().collect(),
})
}
}
#[proc_macro_attribute]
pub fn trace_vars(metadata: TokenStream, input: TokenStream) -> TokenStream {
// parsing rust function to easy to use struct
let input_fn = parse_macro_input!(input as ItemFn);
let mut args = parse_macro_input!(metadata as Args);
let output = args.fold_item_fn(input_fn);
TokenStream::from(quote! {#output})
}