1use std::iter::Peekable;
2
3use extension_traits::extension as ext;
4use maflow::*;
5use proc_macro2::token_stream::IntoIter;
6use syn::{token::For, *};
7
8pub use {convert_case, proc_macro2, quote, syn};
9
10pub use convert_case::{Case,Casing};
13 pub use quote::{quote as qt, quote_spanned as qts, ToTokens};
14 pub use proc_macro2::{
15 Delimiter, Span, TokenStream, TokenTree, Group, Ident, Punct, Literal };
18 pub use syn::spanned::Spanned;
19
20fn imp_hlpr(attr:TokenStream,imp_block:TokenStream) -> TokenStream {
23 let mut iter = attr.peek_iter();
24 let create_trait = iter.devour_punct('*');
25 let maybe_path = iter.peek().is_some().then_some(TokenStream::from_iter(iter));
26 let mut input: ItemImpl = syn::parse2(imp_block).unwrap();
27 let path_tok = maybe_path.unwrap_or_else(||{
28 let self_ty = input.self_ty.to_token_stream().to_string()
29 .chars().filter(|v|v.is_alphanumeric())
30 .collect::<String>().to_case(Case::Pascal);
31 let first_fn = input.items.iter().find_map(|a|match a {
32 ImplItem::Fn(a) => Some(a.sig.ident.to_string().to_case(Case::Pascal)), _=>None
33 }).unwrap();
34 (self_ty+&first_fn+"Ext").ident().into_token_stream()
35 });
36 let path: Path = parse2(path_tok).unwrap();
37 let mut out = qt![];
38 if !create_trait {
39 input.trait_ = Some((None,path.clone(),For::default()));
40 }
41 out.extend(input.into_token_stream());
42 if create_trait {
43 out = qt![ #[ext(pub trait #path)] #out ];
44 }
45 out
46 }
47
48 pub fn imp (attr:TokenStream,stream:TokenStream) -> TokenStream {
57 let is_impl = stream.clone().into_iter().find_map(|t| match t {
58 TokenTree::Ident(i) if i == "impl" => Some(true),
59 TokenTree::Ident(i) if i == "fn" => Some(false),
60 _ => None,
61 }).unwrap_or(false);
62 if is_impl {
63 imp_hlpr(attr,stream)
64 } else {
65 let mut split = attr.peek_iter().split_punct('|');
66 let mut iter = split.remove(0).peek_iter();
67 let create_unit = iter.devour_punct('*');
68 let name = iter.next().unwrap();
69 let gens: Generics = parse2(TokenStream::from_iter(iter)).unwrap();
70 let (gen_impl,gen_typ,gen_where) = gens.split_for_impl();
71 let mut imp_block = qt!( impl #gen_impl #name #gen_typ #gen_where {#stream} );
72 if let Some(tok) = split.pop() {
73 imp_block = imp_hlpr(tok,imp_block);
74 }
75 let unit = if create_unit { qt![pub struct #name;] } else { qt![] };
76 qt!{#unit #imp_block}
77
78
79}
96 }
97
98
99#[ext(pub trait StringProcExt)]
103 impl String {
104 fn ident(&self) -> Ident {Ident::new(self,Span::call_site())}
105 fn ident_span(&self,span:Span) -> Ident {Ident::new(self,span)}
106 }
107
108 impl StringProcExt for &str {
109 fn ident(&self) -> Ident {Ident::new(self,Span::call_site())}
110 fn ident_span(&self,span:Span) -> Ident {Ident::new(self,span)}
111 }
112
113
114#[derive(Default)]
118 pub enum Check<T,M> {#[default] None, Some(T), Maybe(M)}
119
120
121macro_rules! is_any {
124 ($self:ident = $var:ident) => {match $self {Self::$var(_) => true, _ => false}};
125 (*$self:ident = $var:ident) => {match $self {Self::$var => true, _ => false}};
126 }
127
128 macro_rules! unwrpr {($self:ident $(.$meth:ident($($tt:tt)*))* = $var:ident) => {
129 match $self $(.$meth($($tt)*))* {TokenTree::$var(v) => v, _ => panic!{"deki-rs|proc: Risk Failed!"}}
130 }}
131
132 macro_rules! checker {($self:ident::$var:ident $block:expr) => {
133 match $self {Self::$var(v) => $block(v), _ => Default::default()}
134 }}
135
136 #[ext(pub trait DekiTokenTreeExt)]
137 impl TokenTree {
138
139 #[inline] fn is_any_punct(&self) -> bool {is_any!(self = Punct)}
141 #[inline] fn is_any_ident(&self) -> bool {is_any!(self = Ident)}
142 #[inline] fn is_any_group(&self) -> bool {is_any!(self = Group)}
143 #[inline] fn is_any_literal(&self) -> bool {is_any!(self = Literal)}
144
145 #[inline] fn unwrap_punct(self) -> Punct {unwrpr!(self = Punct)}
147 #[inline] fn unwrap_ident(self) -> Ident {unwrpr!(self = Ident)}
148 #[inline] fn unwrap_group(self) -> Group {unwrpr!(self = Group)}
149 #[inline] fn unwrap_literal(self) -> Literal {unwrpr!(self = Literal)}
150
151 #[inline]
153 #[allow(clippy::redundant_closure)]
154 fn map_punct<O:Default,F:FnOnce(&Punct)->O>(&self,check:F) -> O {checker!(self::Punct|v|check(v))}
155 #[inline]
156 #[allow(clippy::redundant_closure)]
157 fn map_ident<O:Default,F:FnOnce(&Ident)->O>(&self,check:F) -> O {checker!(self::Ident|v|check(v))}
158 #[inline]
159 #[allow(clippy::redundant_closure)]
160 fn map_group<O:Default,F:FnOnce(&Group)->O>(&self,check:F) -> O {checker!(self::Group|v|check(v))}
161 #[inline]
162 #[allow(clippy::redundant_closure)]
163 fn map_literal<O:Default,F:FnOnce(&Literal)->O>(&self,check:F) -> O {checker!(self::Literal|v|check(v))}
164
165 #[inline] fn is_numeric(&self) -> bool {self.map_literal(move|x|x.is_numeric())}
167 #[inline] fn is_string(&self,text:&str) -> bool {self.to_string().as_str() == text}
168 #[inline] fn is_punct(&self,punct:char) -> bool {self.map_punct(move|x|x.as_char()==punct)}
169
170 #[inline] fn inner_tokens(&self) -> TokenStream {match self{
174 TokenTree::Group(g) => g.stream(),
175 _ => self.to_token_stream()
176 }}
177
178 }
179
180 #[ext(pub trait DekiOptTokenTreeExt)]
181 impl <'a> Option<&'a TokenTree> {
182
183 #[inline] fn is_any_punct(&self) -> bool {exit![t=self];t.is_any_punct()}
185 #[inline] fn is_any_ident(&self) -> bool {exit![t=self];t.is_any_ident()}
186 #[inline] fn is_any_group(&self) -> bool {exit![t=self];t.is_any_group()}
187 #[inline] fn is_any_literal(&self) -> bool {exit![t=self];t.is_any_literal()}
188
189 #[inline] fn unwrap_punct(self) -> &'a Punct {unwrpr!(self.unwrap() = Punct)}
191 #[inline] fn unwrap_ident(self) -> &'a Ident {unwrpr!(self.unwrap() = Ident)}
192 #[inline] fn unwrap_group(self) -> &'a Group {unwrpr!(self.unwrap() = Group)}
193 #[inline] fn unwrap_literal(self) -> &'a Literal {unwrpr!(self.unwrap() = Literal)}
194
195 #[inline] fn map_punct<O:Default,F:FnOnce(&Punct)->O>(&self,check:F) -> O {exit![t=self];t.map_punct(check)}
197 #[inline] fn map_ident<O:Default,F:FnOnce(&Ident)->O>(&self,check:F) -> O {exit![t=self];t.map_ident(check)}
198 #[inline] fn map_group<O:Default,F:FnOnce(&Group)->O>(&self,check:F) -> O {exit![t=self];t.map_group(check)}
199 #[inline] fn map_literal<O:Default,F:FnOnce(&Literal)->O>(&self,check:F) -> O {exit![t=self];t.map_literal(check)}
200
201 #[inline] fn is_numeric(&self) -> bool {exit![t=self];t.is_numeric()}
203 #[inline] fn is_string(&self,text:&str) -> bool {exit![t=self];t.is_string(text)}
204 #[inline] fn is_punct(&self,punct:char) -> bool {exit![t=self];t.is_punct(punct)}
205
206 }
207
208
209#[ext(pub trait IdentExt)]
212 impl Ident {
213 fn to_case(&self,case:Case) -> Ident {
214 Ident::new(&self.to_string().to_case(case),self.span())
215 }
216 }
217
218 #[ext(pub trait LiteralExt)]
219 impl Literal {
220 fn is_numeric(&self) -> bool {
221 match self.to_string().chars().next(){
222 Some(first) => first.is_numeric(),
223 _ => false
224 }
225 }
226 #[inline] fn try_int(&self) -> Result<LitInt> {parse2(self.into_token_stream())}
227 #[inline] fn try_float(&self) -> Result<LitFloat> {parse2(self.into_token_stream())}
228 }
229
230 #[ext(pub trait PunctExt)]
231 impl Punct {
232
233 }
234
235 #[ext(pub trait DelimiterExt)]
236 impl Delimiter {
237 #[inline] fn is_parenthesis(&self) -> bool {is_any!(*self = Parenthesis)}
238 #[inline] fn is_brace(&self) -> bool {is_any!(*self = Brace)}
239 #[inline] fn is_bracket(&self) -> bool {is_any!(*self = Bracket)}
240 #[inline] fn is_none(&self) -> bool {is_any!(*self = None)}
241 }
242
243
244#[derive(Default)]
252 pub enum Step<T,M> {#[default] None, Base(T), Shift(M)}
253
254 impl <T,M> Step <T,M> {
255 pub fn risk_shift(self) -> M {match self {
257 Self::Shift(m) => m,
258 _ => panic!{}
259 }}
260 pub fn shift_or(self,m:M) -> M {match self {
262 Self::Shift(m) => m,
263 _ => m
264 }}
265 }
266
267 #[ext(pub trait TokenStreamExt)]
268 impl TokenStream {
269 fn peek_iter(self) -> PeekIter {
270 self.into_iter().peekable()
271 }
272 fn with_span(self,span:Span) -> Self {
273 Self::from_iter(self.into_iter().map(|mut a|{a.set_span(span);a}))
274 }
275 fn as_vec(self) -> Vec<TokenTree> {
276 self.into_iter().collect()
277 }
278
279 fn replace_atoms(self,func:fn(TokenTree)->TokenTree) -> Self {
280 Self::from_iter(self.into_iter().map(|a|match &a {
281 TokenTree::Group(g) => TokenTree::Group(Group::new(g.delimiter(),g.stream().replace_atoms(func))),
282 _ => func(a)
283 }))
284 }
285
286 }
287
288 pub type PeekIter = Peekable<IntoIter>;
290
291 #[ext(pub trait TreeIterExt)]
292 impl PeekIter {
293
294 #[inline] fn devour_punct(&mut self,p:char) -> bool {self.next_if(|v|v.is_punct(p)).is_some()}
296 fn collect_til_punct(&mut self,punct:char) -> Vec<TokenTree> {
302 let mut out = vec![];
303 while let Some(a) = self.next_if(|a|!a.is_punct(punct)){
304 out.push(a);
305 }
306 out
307 }
308
309 fn skip_puncts(&mut self,stoppers:&str) -> Vec<TokenTree> {
311 let mut out = vec![];
312 while let Some(TokenTree::Punct(pnc)) = self.peek() {
313 if stoppers.contains(pnc.as_char()) {return out}
314 out.push(self.next().unwrap());
315 }
316 out
317 }
318
319 fn next_if_num(&mut self) -> Option<Literal> {
321 exit![if !self.peek().is_numeric()];
322 self.next().map(|l|l.unwrap_literal())
323 }
324
325 fn try_next_float(&mut self) -> Option<(f32,LitFloat)> {
327 exit![lit = self.next_if_num()];
328 let lit: LitFloat = lit.clone().into();
329 kill![num = lit.base10_parse::<f32>()];
330 Some((num,lit))
331 }
332
333 fn peek_punct(&mut self) -> char {
335 exit![>(peek = self.peek())'n'];
336 exit![>(*TokenTree::Punct(p) = peek)'n'];
337 p.as_char()
338 }
339
340 fn split_punct(self,punct:char) -> Vec<TokenStream> {
342 let mut out = vec![];
343 let mut curr = vec![];
344 for tree in self {
345 if tree.is_punct(punct){
346 if !curr.is_empty(){
347 out.push(TokenStream::from_iter(std::mem::take(&mut curr)));
348 }
349 continue
350 }
351 curr.push(tree);
352 }
353 if !curr.is_empty(){
354 out.push(TokenStream::from_iter(curr));
355 }
356 out
357 }
358 }
359
360
361