ruex_macro/impls/
contract_aspect.rs

1#![allow(dead_code)]
2use std::{
3    collections::{HashMap, VecDeque},
4    fmt,
5    net::UdpSocket,
6};
7
8// use proc_macro::TokenStream;
9use proc_macro2::{Punct, Spacing, TokenStream as TokenStream2, TokenTree};
10use quote::{format_ident, quote};
11use syn::{
12    parse::{Parse, ParseStream, Result},
13    punctuated::Punctuated,
14    visit_mut::VisitMut,
15    Attribute, Expr, ExprLit, ExprPath, Lit, Meta, MetaNameValue, PathSegment, Token, TraitItem,
16    TraitItemMethod,
17};
18
19use companion::{companion_addr, Response, Task};
20
21use crate::MAX_UDP_PAYLOAD;
22
23pub struct AspectJointPoint<'a> {
24    pub stream: &'a TokenStream2,
25}
26
27impl<'a> VisitMut for AspectJointPoint<'a> {
28    fn visit_expr_mut(&mut self, item: &mut Expr) {
29        if let Expr::Call(ref node) = item {
30            if let Expr::Path(call) = node.func.as_ref() {
31                let segments = &call.path.segments;
32                if segments.len() == 2 {
33                    if let (Some(first), Some(last)) = (segments.first(), segments.last()) {
34                        if first.ident.to_string() == "AspectJointPoint"
35                            && last.ident.to_string() == "proceed"
36                        {
37                            // prepare variables
38                            let stream = self.stream;
39                            *item = syn::parse_quote!(#stream);
40                        }
41                    }
42                }
43            }
44        }
45
46        // Delegate to the default impl to visit nested expressions.
47        syn::visit_mut::visit_expr_mut(self, item);
48    }
49}
50
51#[derive(Default, Debug)]
52pub struct Aspect {
53    pub name: String,
54    pub docs: VecDeque<String>,
55    pub before: Option<TraitItemMethod>,
56    pub after: Option<TraitItemMethod>,
57    pub around: Option<TraitItemMethod>,
58}
59
60impl Aspect {
61    pub fn new(attr: TokenStream2) -> Self {
62        // prefetch from attrs
63        match syn::parse2::<syn::TypePath>(attr.clone()) {
64            Ok(_) => {}
65            Err(_) => panic!("Usage: #[aspect(std::fmt::Display)]"),
66        }
67
68        let key = attr.to_string().replace(" :: ", "::");
69
70        let addr = companion_addr();
71
72        let socket = UdpSocket::bind("[::]:0").unwrap();
73        socket.connect(addr).unwrap();
74        let mut buf = [0; MAX_UDP_PAYLOAD];
75
76        socket.send(&Task::Get(&key).as_bytes()).unwrap();
77        let (len, _src) = socket.recv_from(&mut buf).unwrap();
78        let resp = Response::from(&buf[..len]);
79
80        if let Response::String(data) = resp {
81            let item_trait: syn::ItemTrait = syn_serde::json::from_str(&data).unwrap();
82            let mut aspect = Aspect::default();
83            aspect.name = key;
84            aspect.docs = collect_docs(&item_trait.attrs);
85
86            // construct proto
87            for item in item_trait.items.iter() {
88                match item {
89                    TraitItem::Method(method) => {
90                        // here
91                        let name = method.sig.ident.to_string();
92                        // println!("Sig {}", name);
93                        match name.as_str() {
94                            "before" => aspect.before = Some(method.clone()),
95                            "after" => aspect.after = Some(method.clone()),
96                            "around" => aspect.around = Some(method.clone()),
97                            _ => {
98                                println!("Incompatible Aspect trait")
99                            }
100                        }
101                    }
102                    _ => {
103                        println!("Incompatible Aspect trait")
104                    }
105                }
106            }
107
108            aspect
109        } else {
110            panic!("Aspect is not registered")
111        }
112    }
113
114    pub fn documentation(&self) -> VecDeque<String> {
115        let mut output: VecDeque<String> = VecDeque::new();
116
117        let mut before_docs: VecDeque<String> = VecDeque::new();
118        let mut after_docs: VecDeque<String> = VecDeque::new();
119        let mut around_docs: VecDeque<String> = VecDeque::new();
120
121        if let Some(ref method) = self.before {
122            before_docs = collect_docs(&method.attrs);
123        }
124
125        if let Some(ref method) = self.around {
126            around_docs = collect_docs(&method.attrs);
127        }
128
129        if let Some(ref method) = self.after {
130            after_docs = collect_docs(&method.attrs);
131        }
132
133        // if there something in documentations
134        if !self.docs.is_empty()
135            || !before_docs.is_empty()
136            || !after_docs.is_empty()
137            || !around_docs.is_empty()
138        {
139            output.push_back(format!(" ### {}", self.name));
140            self.docs.iter().for_each(|item| {
141                output.push_back(item.clone());
142            });
143
144            if !before_docs.is_empty() {
145                // output.push_back(String::from(""));
146                output.push_back(String::from(" - __Before:__"));
147
148                before_docs.iter().for_each(|item| {
149                    output.push_back(item.clone());
150                });
151            }
152
153            if !around_docs.is_empty() {
154                // output.push_back(String::from(""));
155                output.push_back(String::from(" - __Around:__"));
156
157                around_docs.iter().for_each(|item| {
158                    output.push_back(item.clone());
159                });
160            }
161
162            if !after_docs.is_empty() {
163                // output.push_back(String::from(""));
164                output.push_back(String::from(" - __After:__"));
165
166                after_docs.iter().for_each(|item| {
167                    output.push_back(item.clone());
168                });
169            }
170        }
171
172        output
173    }
174}
175
176fn collect_docs(attrs: &Vec<Attribute>) -> VecDeque<String> {
177    let mut docs: VecDeque<String> = VecDeque::new();
178    attrs.iter().for_each(|attr| {
179        // Collect docs attributes
180        if attr.path.is_ident("doc") {
181            match attr.parse_meta().unwrap() {
182                Meta::NameValue(MetaNameValue {
183                    lit: Lit::Str(lit_str),
184                    ..
185                }) => {
186                    docs.push_back(lit_str.value());
187                }
188                _ => {}
189            }
190        }
191    });
192    docs
193}
194
195// detect ranges separated by implication and return
196fn stream_ranges(input: &Vec<TokenTree>) -> Vec<(usize, usize)> {
197    let mut ranges: Vec<(usize, usize)> = vec![];
198
199    let mut tail = &TokenTree::Punct(Punct::new(' ', Spacing::Alone));
200    let mut start_current = 0;
201
202    // split for  ->
203    for (idx, attr) in input.iter().enumerate() {
204        if let TokenTree::Punct(cur) = attr {
205            if cur.as_char() == '>' && cur.spacing() == Spacing::Alone {
206                if let TokenTree::Punct(prev) = tail {
207                    if prev.as_char() == '-' && prev.spacing() == Spacing::Joint {
208                        ranges.push((start_current, idx - 1));
209                        start_current = idx + 1;
210                    }
211                }
212            }
213        }
214
215        tail = attr;
216    }
217
218    if start_current < input.len() {
219        ranges.push((start_current, input.len()));
220    }
221
222    ranges
223}
224
225/// Checking-mode of a contract.
226#[derive(Debug, Copy, Clone, Eq, PartialEq)]
227pub enum Mode {
228    /// Always check contract
229    Always,
230    /// Never check contract
231    Disabled,
232    /// Check contract only in debug builds
233    Debug,
234    /// Check contract only in `#[cfg(test)]` configurations
235    Test,
236    /// Check the contract and print information upon violation, but don't abort
237    /// the program.
238    LogOnly,
239}
240
241impl Mode {
242    /// Return the prefix of attributes of `self` mode.
243    pub fn name(self) -> Option<&'static str> {
244        match self {
245            Mode::Always => Some(""),
246            Mode::Disabled => None,
247            Mode::Debug => Some("debug_"),
248            Mode::Test => Some("test_"),
249            Mode::LogOnly => None,
250        }
251    }
252
253    /// Computes the contract type based on feature flags.
254    pub fn final_mode(self) -> Self {
255        // disabled ones can't be "forced", test ones should stay test, no
256        // matter what.
257        if self == Mode::Disabled || self == Mode::Test {
258            return self;
259        }
260
261        if cfg!(feature = "disable_contracts") {
262            Mode::Disabled
263        } else if cfg!(feature = "override_debug") {
264            // log is "weaker" than debug, so keep log
265            if self == Mode::LogOnly {
266                self
267            } else {
268                Mode::Debug
269            }
270        } else if cfg!(feature = "override_log") {
271            Mode::LogOnly
272        } else {
273            self
274        }
275    }
276}
277
278/// The different contract types.
279#[derive(Debug, Copy, Clone, PartialEq, Eq)]
280pub enum Type {
281    Requires,
282    Ensures,
283    Invariant,
284    Aspect,
285}
286
287impl Type {
288    /// Get the name that is used as a message-prefix on violation of a
289    /// contract.
290    pub fn message_name(self) -> &'static str {
291        match self {
292            Type::Requires => "Pre-condition",
293            Type::Ensures => "Post-condition",
294            Type::Invariant => "Invariant",
295            Type::Aspect => "Invariant",
296        }
297    }
298
299    /// Determine the type and mode of an identifier.
300    pub fn type_and_mode(ident: &str) -> Option<(Type, Mode)> {
301        match ident {
302            "aspect" => Some((Type::Aspect, Mode::Always)),
303            "requires" => Some((Type::Requires, Mode::Always)),
304            "ensures" => Some((Type::Ensures, Mode::Always)),
305            "invariant" => Some((Type::Invariant, Mode::Always)),
306            "debug_requires" => Some((Type::Requires, Mode::Debug)),
307            "debug_ensures" => Some((Type::Ensures, Mode::Debug)),
308            "debug_invariant" => Some((Type::Invariant, Mode::Debug)),
309            "test_requires" => Some((Type::Requires, Mode::Test)),
310            "test_ensures" => Some((Type::Ensures, Mode::Test)),
311            "test_invariant" => Some((Type::Invariant, Mode::Test)),
312            _ => None,
313        }
314    }
315}
316
317// Contain single part of contract case as vector of Rule expressions
318#[derive(Debug)]
319pub struct CaseRule(Vec<RuleExpression>);
320
321impl CaseRule {
322    fn add(&mut self, value: RuleExpression) {
323        self.0.push(value);
324    }
325}
326
327impl Default for CaseRule {
328    fn default() -> Self {
329        Self(Default::default())
330    }
331}
332
333// Describe rule expression
334#[derive(Debug)]
335enum RuleExpression {
336    If(Expr),
337    Expr(Expr),
338    // Desc(String),
339}
340
341pub struct Contract {
342    pub ty: Type,
343    pub mode: Mode,
344    pub desc: Option<String>,
345    pub rules: Vec<CaseRule>,
346    // variable declarations
347    pub decls: HashMap<String, Expr>,
348}
349
350impl Contract {
351    pub fn syntax(&self) -> Vec<TokenStream2> {
352        let assert = match self.mode {
353            Mode::Always => format_ident!("assert"),
354            Mode::Debug | Mode::Test => {
355                format_ident!("debug_assert")
356            }
357            Mode::Disabled | Mode::LogOnly => return vec![],
358        };
359
360        self.rules
361            .iter()
362            .map(|rule| {
363                let mut holder = quote! {};
364
365                for expr in rule.0.iter().rev() {
366                    match expr {
367                        RuleExpression::If(e) => {
368                            holder = quote! {
369                                if (#e) {
370                                    #holder
371                                }
372                            };
373                        }
374                        RuleExpression::Expr(e) => match self.desc {
375                            Some(ref desc) => {
376                                holder = quote! {
377                                    #assert!(#e, #desc);
378                                };
379                            }
380                            None => {
381                                holder = quote! {
382                                    #assert!(#e);
383                                };
384                            }
385                        },
386                    }
387                }
388                holder
389            })
390            .collect()
391    }
392}
393
394impl fmt::Debug for Contract {
395    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
396        match &self.desc {
397            Some(desc) => {
398                write!(
399                    f,
400                    "{:?}:{:?}, {} rules [{desc}]",
401                    self.mode,
402                    self.ty,
403                    self.rules.len()
404                )
405            }
406            None => {
407                write!(
408                    f,
409                    "{:?}:{:?}, {} rules",
410                    self.mode,
411                    self.ty,
412                    self.rules.len()
413                )
414            }
415        }
416    }
417}
418
419impl Contract {
420    pub fn new(ty: Type, mode: Mode) -> Self {
421        Self {
422            ty,
423            mode,
424            desc: None,
425            rules: Vec::new(),
426            decls: HashMap::new(),
427        }
428    }
429
430    // Parse attribures from TokenStream into rules
431    //
432    pub fn parse_attributes(&mut self, stream: TokenStream2) {
433        // should split stream by implication first, instead coma
434        let stream = stream.into_iter().collect::<Vec<_>>();
435
436        let ranges = stream_ranges(&stream);
437
438        // `peekable` to look at the next element of the iterator without consuming it
439        let mut range_iter = ranges.iter().peekable();
440
441        // expressions placeholder
442        let mut rule = CaseRule::default();
443        while let Some(range) = range_iter.next() {
444            let stream = stream[range.0..range.1]
445                .iter()
446                .map(|x| x.clone())
447                .collect::<TokenStream2>();
448            let Segment { expressions } = syn::parse2(stream).unwrap();
449
450            let is_last_segment = range_iter.peek().is_none();
451
452            let mut expr_iter = expressions.iter().peekable();
453            while let Some(expr) = expr_iter.next() {
454                let is_last_expr = expr_iter.peek().is_none();
455
456                if !is_last_segment && is_last_expr {
457                    match expr {
458                        Expr::Lit(_) => panic!("Description should be last element"),
459                        _ => {
460                            let mut expr = expr.clone();
461                            let mut replacer = OldPseudo::default();
462                            replacer.visit_expr_mut(&mut expr);
463
464                            if self.ty != Type::Ensures && !replacer.items.is_empty() {
465                                panic!("Only ensures support 'old' pseudo-expressions")
466                            }
467
468                            replacer.items.into_iter().for_each(|(k, v)| {
469                                self.decls.insert(k, v);
470                            });
471
472                            rule.add(RuleExpression::If(expr));
473                        }
474                    }
475                } else if is_last_segment && !is_last_expr {
476                    match expr {
477                        Expr::Lit(_) => panic!("Description should be last element"),
478                        _ => {
479                            let mut expr = expr.clone();
480                            let mut replacer = OldPseudo::default();
481                            replacer.visit_expr_mut(&mut expr);
482
483                            if self.ty != Type::Ensures && !replacer.items.is_empty() {
484                                panic!("Only ensures support 'old' pseudo-expressions")
485                            }
486
487                            replacer.items.into_iter().for_each(|(k, v)| {
488                                self.decls.insert(k, v);
489                            });
490
491                            rule.add(RuleExpression::Expr(expr));
492                            self.rules.push(rule);
493                            rule = CaseRule::default();
494                        }
495                    }
496                } else if is_last_segment && is_last_expr {
497                    // get desc if exists
498                    match expr {
499                        Expr::Lit(ExprLit {
500                            lit: Lit::Str(token),
501                            ..
502                        }) => {
503                            self.desc = Some(token.value());
504                        }
505                        _ => {
506                            let mut expr = expr.clone();
507                            let mut replacer = OldPseudo::default();
508                            replacer.visit_expr_mut(&mut expr);
509
510                            if self.ty != Type::Ensures && !replacer.items.is_empty() {
511                                panic!("Only ensures support 'old' pseudo-expressions")
512                            }
513
514                            replacer.items.into_iter().for_each(|(k, v)| {
515                                self.decls.insert(k, v);
516                            });
517
518                            rule.add(RuleExpression::Expr(expr));
519                            self.rules.push(rule);
520                            rule = CaseRule::default();
521                        }
522                    }
523                } else {
524                    match expr {
525                        Expr::Lit(_) => panic!("Description should be last element"),
526                        _ => {
527                            let mut expr = expr.clone();
528                            let mut replacer = OldPseudo::default();
529                            replacer.visit_expr_mut(&mut expr);
530
531                            if self.ty != Type::Ensures && !replacer.items.is_empty() {
532                                panic!("Only ensures support 'old' pseudo-expressions")
533                            }
534
535                            replacer.items.into_iter().for_each(|(k, v)| {
536                                self.decls.insert(k, v);
537                            });
538
539                            rule.add(RuleExpression::Expr(expr));
540                            self.rules.push(rule);
541                            rule = CaseRule::default();
542                        }
543                    }
544                }
545            }
546        }
547    }
548}
549
550// faster trim whitespace
551pub fn trim_whitespace(s: &str) -> String {
552    let mut new_str = s.trim().to_owned();
553    let mut prev = ' '; // The initial value doesn't really matter
554    new_str.retain(|ch| {
555        let result = ch != ' ' || prev != ' ';
556        prev = ch;
557        result
558    });
559    new_str
560}
561
562#[derive(Debug, Default)]
563struct OldPseudo {
564    items: HashMap<String, Expr>,
565}
566
567impl VisitMut for OldPseudo {
568    fn visit_expr_mut(&mut self, item: &mut Expr) {
569        if let Expr::Call(ref node) = item {
570            if let syn::Expr::Path(call) = node.func.as_ref() {
571                let segments = &call.path.segments;
572                if let Some(path) = segments.first() {
573                    if path.ident.to_string() == "old" {
574                        // println!("Call: {item:?}");
575                        let name = format!("{}", quote!(#node));
576                        let cleaned: String = name
577                            .chars()
578                            .filter_map(|x| match x {
579                                'A'..='Z' | 'a'..='z' | '0'..='9' | ' ' => Some(x),
580                                _ => None,
581                            })
582                            .collect();
583
584                        let name = trim_whitespace(&cleaned)
585                            .split(' ')
586                            .filter(|s| !s.is_empty())
587                            .collect::<Vec<_>>()
588                            .join("_");
589
590                        let var = format_ident!("{name}");
591
592                        let old_arg = node
593                            .args
594                            .first()
595                            .expect("The 'old' pseudo-function have exactly one parameter");
596
597                        // store node as `old` pseudo-expressions
598                        self.items.insert(name, old_arg.clone());
599
600                        let expr: ExprPath = syn::parse_quote!(#var);
601                        *item = Expr::Path(expr);
602                    }
603                }
604            }
605        }
606        // Delegate to the default impl to visit nested expressions.
607        syn::visit_mut::visit_expr_mut(self, item);
608    }
609}
610
611#[derive(Debug, Clone)]
612pub struct Segment {
613    pub expressions: Vec<Expr>,
614}
615
616impl Parse for Segment {
617    fn parse(input: ParseStream) -> Result<Self> {
618        let vars = Punctuated::<Expr, Token![,]>::parse_terminated(input).unwrap();
619        let expressions: Vec<Expr> = vars.into_iter().collect();
620
621        // println!("{items:#?}");
622        Ok(Segment { expressions })
623    }
624}
625
626#[derive(Default, Debug)]
627pub struct ContractAspectState {
628    pub docs: VecDeque<String>,
629    pub requires: Vec<Contract>,
630    pub invariants: Vec<Contract>,
631    pub ensures: Vec<Contract>,
632    pub aspects: Vec<Aspect>,
633}
634
635impl ContractAspectState {
636    // Process rest of contract attributes
637    // and keep others, to generate new attributes set
638    pub fn process(&mut self, attrs: &Vec<Attribute>) -> Vec<Attribute> {
639        attrs
640            .iter()
641            .filter_map(|attr| {
642                // let len = attr.path.segments.len();
643                if let Some(PathSegment { ident, .. }) = attr.path.segments.last() {
644                    let pair = Type::type_and_mode(&ident.to_string());
645                    if let Some((ty, mode)) = pair {
646                        // create case
647                        match ty {
648                            Type::Requires | Type::Ensures | Type::Invariant => {
649                                let mut case = Contract::new(ty, mode);
650                                let tokens = attr.tokens.clone().into_iter().collect::<Vec<_>>();
651                                assert!(
652                                    tokens.len() == 1,
653                                    "Wrong contract sintax: not parenthesized expression"
654                                );
655
656                                if let Some(TokenTree::Group(group)) = tokens.first() {
657                                    case.parse_attributes(group.stream());
658                                    match ty {
659                                        Type::Requires => self.requires.push(case),
660                                        Type::Ensures => self.ensures.push(case),
661                                        Type::Invariant => self.invariants.push(case),
662                                        _ => unreachable!(),
663                                    }
664                                } else {
665                                    panic!("Wrong contract sintax: not parenthesized expression")
666                                }
667                            }
668                            Type::Aspect => {
669                                let tokens = attr.tokens.clone().into_iter().collect::<Vec<_>>();
670                                assert!(
671                                    tokens.len() == 1,
672                                    "Wrong aspect sintax: not parenthesized expression"
673                                );
674                                if let Some(TokenTree::Group(group)) = tokens.first() {
675                                    let aspect = Aspect::new(group.stream());
676                                    self.aspects.push(aspect);
677                                } else {
678                                    panic!("Wrong contract sintax: not parenthesized expression")
679                                }
680                            }
681                        };
682
683                        // Eat contract attribute
684                        None
685                    } else {
686                        // Attribute is not contract
687                        // Collect docs attributes
688                        if attr.path.is_ident("doc") {
689                            match attr.parse_meta().unwrap() {
690                                Meta::NameValue(MetaNameValue {
691                                    lit: Lit::Str(lit_str),
692                                    ..
693                                }) => {
694                                    // println!("{}", lit_str.value());
695                                    self.docs.push_back(lit_str.value());
696                                    None
697                                }
698                                _ => Some(attr.clone()),
699                            }
700                        } else {
701                            Some(attr.clone())
702                        }
703                    }
704                } else {
705                    // Attribute without path
706                    unreachable!()
707                }
708            })
709            .collect::<Vec<_>>()
710    }
711
712    // collect variable declarations from ensure cases
713    pub fn variables(&self) -> Vec<TokenStream2> {
714        let mut decls: HashMap<String, Expr> = HashMap::new();
715        self.ensures.iter().for_each(|case| {
716            case.decls.iter().for_each(|(name, expr)| {
717                decls.insert(name.to_string(), expr.clone());
718            });
719        });
720
721        decls
722            .into_iter()
723            .map(|(name, expr)| {
724                let name = format_ident!("{name}");
725                quote! {
726                    let #name = #expr;
727                }
728            })
729            .collect::<Vec<_>>()
730    }
731}
732
733pub trait SyntaxAndDocs {
734    fn generate(&self) -> (Vec<TokenStream2>, Vec<String>);
735}
736
737impl SyntaxAndDocs for Vec<Contract> {
738    fn generate(&self) -> (Vec<TokenStream2>, Vec<String>) {
739        let mut docs = vec![];
740        let stream = self
741            .iter()
742            .map(|case| {
743                if let Some(ref desc) = case.desc {
744                    docs.push(format!(" - {}", desc))
745                }
746                case.syntax()
747            })
748            .flatten()
749            .collect::<Vec<_>>();
750        (stream, docs)
751    }
752}
753
754// process macro attribute by initiating currentt case and handle rest of cases
755pub(crate) fn contracts_aspect(
756    ty: Type,
757    mode: Mode,
758    attrs: TokenStream2,
759    item: TokenStream2,
760) -> TokenStream2 {
761    let mut state: ContractAspectState = ContractAspectState::default();
762
763    // process primary contract case
764
765    match ty {
766        Type::Requires | Type::Ensures | Type::Invariant => {
767            let mut case = Contract::new(ty, mode);
768            case.parse_attributes(attrs);
769
770            match ty {
771                Type::Requires => state.requires.push(case),
772                Type::Ensures => state.ensures.push(case),
773                Type::Invariant => state.invariants.push(case),
774                _ => unreachable!(),
775            }
776        }
777        Type::Aspect => {
778            state.aspects.push(Aspect::new(attrs));
779        }
780    }
781
782    // process rest of contract cases
783    let input: syn::ItemFn = syn::parse2(item.clone().into()).unwrap();
784
785    let syn::ItemFn {
786        attrs,
787        vis,
788        sig,
789        block,
790    } = input;
791
792    let attrs = state.process(&attrs);
793
794    let variables = state.variables();
795
796    // генерация синтаксиса и документации
797    let mut contract_docs: VecDeque<String> = VecDeque::new();
798
799    let (requires, docs) = state.requires.generate();
800    contract_docs.extend(docs);
801
802    let (invariants, docs) = state.invariants.generate();
803    contract_docs.extend(docs);
804
805    let (ensures, docs) = state.ensures.generate();
806    contract_docs.extend(docs);
807
808    if !contract_docs.is_empty() {
809        contract_docs.push_front(String::from(" # Contract"));
810    }
811
812    let before = state
813        .aspects
814        .iter()
815        .filter_map(|aspect| {
816            if let Some(item) = &aspect.before {
817                item.default.as_ref().map(|block| {
818                    let stmts = &block.stmts;
819                    quote! {
820                        #(#stmts)*
821                    }
822                })
823            } else {
824                None
825            }
826        })
827        .collect::<Vec<_>>();
828
829    let after = state
830        .aspects
831        .iter()
832        .rev()
833        .filter_map(|aspect| {
834            if let Some(item) = &aspect.after {
835                item.default.as_ref().map(|block| {
836                    let stmts = &block.stmts;
837                    quote! {
838                        #(#stmts)*
839                    }
840                })
841            } else {
842                None
843            }
844        })
845        .collect::<Vec<_>>();
846
847    // Here we should deal with call name )))
848    // For traits we need only change some in output
849    let mut around = quote! {inner()};
850    let mut has_around = false;
851
852    let mut it = state.aspects.iter().rev().peekable();
853    while let Some(aspect) = it.next() {
854        if let Some(item) = &aspect.around {
855            item.default.as_ref().map(|block| {
856                let mut replacer = AspectJointPoint { stream: &around };
857
858                let mut stmts = block.stmts.clone();
859
860                for stmt in stmts.iter_mut() {
861                    replacer.visit_stmt_mut(stmt);
862                }
863
864                if it.peek().is_none() {
865                    around = quote!(#(#stmts)*);
866                } else {
867                    around = quote!({#(#stmts)*});
868                }
869                has_around = true;
870            });
871        }
872    }
873
874    let attrs = {
875        let mut new_attrs: Vec<Attribute> = Vec::new();
876
877        if !state.docs.is_empty() {
878            let mut it = state.docs.iter().peekable();
879            while let Some(comment) = it.next() {
880                if it.peek().is_some() {
881                    new_attrs.push(syn::parse_quote!(#[doc = #comment]));
882                } else if !comment.trim().is_empty() {
883                    new_attrs.push(syn::parse_quote!(#[doc = #comment]));
884                }
885            }
886            new_attrs.push(syn::parse_quote!(#[doc = ""]));
887        }
888
889        if !contract_docs.is_empty() {
890            let mut it = contract_docs.iter().peekable();
891            while let Some(comment) = it.next() {
892                if it.peek().is_some() {
893                    new_attrs.push(syn::parse_quote!(#[doc = #comment]));
894                } else if !comment.trim().is_empty() {
895                    new_attrs.push(syn::parse_quote!(#[doc = #comment]));
896                }
897            }
898            new_attrs.push(syn::parse_quote!(#[doc = ""]));
899        }
900
901        let mut aspect_docs: VecDeque<String> = VecDeque::new();
902        // TODO: Aspects
903        state.aspects.iter().for_each(|aspect| {
904            //
905            let mut docs = aspect.documentation();
906            if !docs.is_empty() {
907                docs.push_back(String::new());
908                aspect_docs.extend(docs);
909            }
910        });
911
912        if !aspect_docs.is_empty() {
913            aspect_docs.push_front(String::from(" # Aspects"));
914            let mut it = aspect_docs.iter().peekable();
915            while let Some(comment) = it.next() {
916                if it.peek().is_some() {
917                    new_attrs.push(syn::parse_quote!(#[doc = #comment]));
918                } else if !comment.trim().is_empty() {
919                    new_attrs.push(syn::parse_quote!(#[doc = #comment]));
920                }
921            }
922            new_attrs.push(syn::parse_quote!(#[doc = ""]));
923        }
924        attrs.iter().cloned().for_each(|attr| {
925            new_attrs.push(attr);
926        });
927        new_attrs
928    };
929
930    let stmts = &block.stmts;
931    let result = if has_around {
932        quote! {
933            let result = {
934                #around
935            };
936        }
937    } else {
938        quote! {
939            let result = inner();
940        }
941    };
942
943    quote! {
944        #(#attrs)* #vis #sig {
945
946            #(#requires)*
947            #(#invariants)*
948
949            #(#variables)*
950
951            let inner = || {
952                #(#stmts)*
953            };
954
955            #(#before)*
956
957            #result
958
959            #(#after)*
960
961            #(#invariants)*
962            #(#ensures)*
963
964            result
965        }
966    }
967}