1use std::collections::HashMap;
2use std::fs;
3use std::fs::OpenOptions;
4use std::io::Write;
5
6use syn::visit::Visit;
7use syn::{Expr, ExprPath, ItemFn, Path};
8
9use crate::labelling::ASTKey;
10use crate::labelling::Label;
11
12pub type Annotations<'a> = HashMap<&'a dyn ASTKey, Label>;
14
15pub type Annotated<'a, T> = (Annotations<'a>, T);
17
18pub const LOOKUP_FILE: &str = "/tmp/annotation_rev_lookup";
19
20struct ASTAnnotator<'a> {
22 annotations: Annotations<'a>,
23 next_label: Label,
24 env: crate::labelling::ScopedContext<syn::Ident, Label>,
25}
26
27impl<'a> ASTAnnotator<'a> {
28 pub fn init() -> Self {
29 let map = HashMap::new();
30 let label = Label::new();
31 let context = Default::default();
32 fs::write(LOOKUP_FILE, "").unwrap();
33 ASTAnnotator {
34 annotations: map,
35 next_label: label,
36 env: context,
37 }
38 }
39
40 pub fn annotations(self) -> HashMap<&'a dyn ASTKey, Label> {
42 self.annotations
43 }
44
45 fn add_binding(&mut self, var: &'a syn::Ident, value: Label) {
46 self.env.add_binding(var.clone(), value)
47 }
48
49 #[allow(dead_code)]
51 pub fn lookup_expr(&mut self, expr: &'a syn::Expr) -> Option<Label> {
52 if let Expr::Path(syn::ExprPath {
53 path: syn::Path { segments, .. },
54 ..
55 }) = expr
56 {
57 let ident = &segments.last().unwrap().ident;
58 self.lookup(ident)
59 } else {
60 self.lookup_ast(expr)
61 }
62 }
63
64 #[allow(dead_code)]
65 pub fn lookup_ast<'b>(&self, ident: &'b dyn ASTKey) -> Option<Label> {
66 self.annotations.get(&ident).map(|v| *v)
67 }
68
69 fn lookup(&mut self, ident: &'a syn::Ident) -> Option<Label> {
70 self.env.lookup(ident)
71 }
72
73 pub fn open_scope(&mut self) {
74 self.env.open_scope()
75 }
76
77 pub fn close_scope(&mut self) {
78 self.env.close_scope()
79 }
80
81 fn new_label(&mut self) -> Label {
82 let label = self.next_label;
83 self.next_label.incr();
84 label
85 }
86}
87
88impl<'a> syn::visit::Visit<'a> for ASTAnnotator<'a> {
89 fn visit_item_fn(&mut self, f: &'a syn::ItemFn) {
90 for arg in f.sig.inputs.iter() {
91 match arg {
92 syn::FnArg::Receiver(_) => unreachable!(),
94 syn::FnArg::Typed(syn::PatType {
95 pat:
96 box syn::Pat::Ident(syn::PatIdent {
97 ident,
98 subpat: None,
99 ..
100 }),
101 ..
102 }) => {
103 let value = self.new_label();
104 self.annotations.insert(ident, value);
105 let mut file = OpenOptions::new()
107 .write(true)
108 .append(true)
109 .open(LOOKUP_FILE)
110 .unwrap();
111 writeln!(file, "{} -> {}", value, ident).unwrap();
112 self.add_binding(ident, value)
113 }
114 _ => (),
115 }
116 }
117 self.visit_block(&f.block);
118 }
119
120 fn visit_block(&mut self, i: &'a syn::Block) {
122 self.open_scope();
123 let res = syn::visit::visit_block(self, i);
124 self.close_scope();
125 res
126 }
127
128 fn visit_local(&mut self, i: &'a syn::Local) {
130 syn::visit::visit_local(self, i);
131 let label = self.new_label();
132 match &i.pat {
133 syn::Pat::Type(syn::PatType {
135 pat: box syn::Pat::Ident(p),
136 ty: box _ty,
137 ..
138 }) => {
139 let ident = &p.ident;
140 self.add_binding(ident, label);
142 self.annotations.insert(ident, label);
143 let mut file = OpenOptions::new()
145 .write(true)
146 .append(true)
147 .open(LOOKUP_FILE)
148 .unwrap();
149 writeln!(file, "{} -> {}", label, ident).unwrap();
150 self.annotations.insert(&i.pat, label);
151 }
152 syn::Pat::Ident(syn::PatIdent {
154 by_ref: _,
155 mutability: _,
156 ident,
157 ..
158 }) => {
159 self.add_binding(ident, label);
160 self.annotations.insert(ident, label);
161 let mut file = OpenOptions::new()
163 .write(true)
164 .append(true)
165 .open(LOOKUP_FILE)
166 .unwrap();
167 writeln!(file, "{} -> {}", label, ident).unwrap();
168 self.annotations.insert(&i.pat, label);
169 }
170 _lb => {
171 let label = self.new_label();
176 self.annotations.insert(i, label);
177 }
178 }
179 }
180
181 fn visit_expr(&mut self, i: &'a Expr) {
182 syn::visit::visit_expr(self, i);
184 match i {
185 Expr::Path(ExprPath {
187 path: Path { segments, .. },
188 ..
189 }) => {
190 let elt = &segments[0];
192 let ident = &elt.ident;
193 let old_label = self.lookup(ident);
194 match old_label {
195 Some(label) => {
196 self.annotations.insert(i, label);
197 }
198 None => {
199 let label = self.new_label();
202 self.annotations.insert(i, label);
203 self.add_binding(ident, label);
204 }
205 }
206 }
207 _ => {
208 let label = self.new_label();
210 self.annotations.insert(i, label);
211 }
212 }
213 }
214}
215
216pub fn annotate_ast<'a>(ast: &'a ItemFn) -> Annotated<'a, &'a ItemFn> {
218 let mut ast_annotation = ASTAnnotator::init();
219
220 ast_annotation.visit_item_fn(ast);
221
222 (ast_annotation.annotations(), ast)
223}