anodized_core/instrument/loops/
mod.rs1#[cfg(test)]
2mod tests;
3
4use syn::{
5 Block, Error, ExprClosure, ExprForLoop, ExprWhile, ItemFn, Result, Stmt, parse_quote,
6 visit_mut::{self, VisitMut},
7};
8
9use crate::{
10 LoopSpec,
11 instrument::{Config, find_spec_attr},
12};
13
14impl Config {
15 pub fn instrument_loops_in_fn_body(&self, body: &mut Block) -> Result<()> {
16 let mut visitor = LoopSpecVisitor::new(self);
17 visitor.visit_block_mut(body);
18 visitor.finish()
19 }
20
21 pub fn instrument_expr_while(&self, spec: LoopSpec, expr_while: &mut ExprWhile) {
22 self.instrument_loop_body(spec, &mut expr_while.body.stmts);
23 }
24
25 pub fn instrument_expr_for_loop(&self, spec: LoopSpec, expr_for_loop: &mut ExprForLoop) {
26 self.instrument_loop_body(spec, &mut expr_for_loop.body.stmts);
27 }
28
29 fn instrument_loop_body(&self, spec: LoopSpec, stmts: &mut Vec<Stmt>) {
30 if self.embed_spec {
31 let maintains_block = Self::build_precondition_fn_body(&spec.maintains);
32 stmts.insert(
33 0,
34 parse_quote! {
35 let __anodized_loop_maintains = #maintains_block;
36 },
37 );
38
39 let let_decreases: Option<Stmt> = spec.decreases.map(|loop_variant| {
40 let expr = loop_variant.expr;
41 parse_quote! {
42 let _ = || #expr;
43 }
44 });
45 stmts.insert(
46 1,
47 parse_quote! {
48 let __anodized_loop_decreases = {
49 #let_decreases
50 };
51 },
52 );
53 }
54 }
55}
56
57struct LoopSpecVisitor<'a> {
58 config: &'a Config,
59 errors: Option<Error>,
60}
61
62impl<'a> LoopSpecVisitor<'a> {
63 fn new(config: &'a Config) -> Self {
64 Self {
65 config,
66 errors: None,
67 }
68 }
69
70 fn finish(self) -> Result<()> {
71 match self.errors {
72 Some(error) => Err(error),
73 None => Ok(()),
74 }
75 }
76
77 fn add_error(&mut self, error: Error) {
78 match &mut self.errors {
79 Some(existing) => existing.combine(error),
80 None => self.errors = Some(error),
81 }
82 }
83}
84
85impl VisitMut for LoopSpecVisitor<'_> {
86 fn visit_expr_while_mut(&mut self, expr_while: &mut ExprWhile) {
87 let attrs = std::mem::take(&mut expr_while.attrs);
88 let (spec_attr, other_attrs) = match find_spec_attr(attrs) {
89 Ok(result) => result,
90 Err(error) => {
91 self.add_error(error);
92 return;
93 }
94 };
95 expr_while.attrs = other_attrs;
96
97 visit_mut::visit_expr_while_mut(self, expr_while);
98
99 let Some(spec_attr) = spec_attr else {
100 return;
101 };
102
103 match spec_attr.parse_args::<LoopSpec>() {
104 Ok(spec) => self
105 .config
106 .instrument_loop_body(spec, &mut expr_while.body.stmts),
107 Err(error) => self.add_error(error),
108 }
109 }
110
111 fn visit_expr_for_loop_mut(&mut self, expr_for_loop: &mut ExprForLoop) {
112 let attrs = std::mem::take(&mut expr_for_loop.attrs);
113 let (spec_attr, other_attrs) = match find_spec_attr(attrs) {
114 Ok(result) => result,
115 Err(error) => {
116 self.add_error(error);
117 return;
118 }
119 };
120 expr_for_loop.attrs = other_attrs;
121
122 visit_mut::visit_expr_for_loop_mut(self, expr_for_loop);
123
124 let Some(spec_attr) = spec_attr else {
125 return;
126 };
127
128 match spec_attr.parse_args::<LoopSpec>() {
129 Ok(spec) => self.config.instrument_expr_for_loop(spec, expr_for_loop),
130 Err(error) => self.add_error(error),
131 }
132 }
133
134 fn visit_expr_closure_mut(&mut self, _expr_closure: &mut ExprClosure) {}
136
137 fn visit_item_fn_mut(&mut self, _item_fn: &mut ItemFn) {}
139}