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
use proc_macro2::TokenStream; use quote::{quote, TokenStreamExt}; use syn::parse::{self, Parse, ParseStream}; use crate::scope::Scope; use crate::section::Section; use crate::section_item::SectionItem; use crate::section_keyword::SectionKeyword; #[derive(Debug, Clone, PartialEq, Eq)] pub struct SectionBody { items: Vec<SectionItem>, } impl SectionBody { pub fn empty() -> Self { Self { items: vec![] } } pub fn new(items: Vec<SectionItem>) -> Self { Self { items } } fn push_stmt(&mut self, stmt: syn::Stmt) { self.items.push(SectionItem::Stmt(stmt)); } fn push_section(&mut self, item: Section) { self.items.push(SectionItem::Sep(item)); } pub fn is_top_level(&self) -> bool { self.items.iter().all(|item| item.is_stmt()) } pub fn get_stmts_before(&self, idx: usize) -> Vec<syn::Stmt> { self.items .iter() .take(idx) .filter_map(|i| i.stmt()) .collect() } pub fn get_stmts_after(&self, idx: usize) -> Vec<syn::Stmt> { self.items .iter() .skip(idx + 1) .filter_map(|i| i.stmt()) .collect() } pub fn items(&self) -> &[SectionItem] { &self.items } pub fn to_tokens_inner(&self, mut scope: Scope, tokens: &mut TokenStream) { let mut stream = vec![]; for (idx, item) in self.items.iter().enumerate() { if let SectionItem::Sep(section) = item { let sb = self.get_stmts_before(idx); let sa = self.get_stmts_after(idx); scope.push_mut(&sb, &sa); let inner = section.quote_inner(scope.clone()); stream.push(quote! { mod catchr_scenarios { use super::*; #inner } }); } } tokens.append_all(stream); } } impl Parse for SectionBody { fn parse(input: ParseStream) -> parse::Result<Self> { let mut body = SectionBody { items: vec![] }; loop { if SectionKeyword::peek(input) { let inner_section = input.parse()?; body.push_section(inner_section); } else if input.is_empty() { break; } else { let next = input.parse::<syn::Stmt>()?; body.push_stmt(next); } } Ok(body) } }