syn_solidity/
macros.rs

1#[cfg(any(feature = "visit", feature = "visit-mut"))]
2macro_rules! make_visitor {
3    (
4        $(#[$attr:meta])*
5        trait $trait_name:ident $(is $mut:ident)?;
6    ) => {
7        make_visitor! {
8            @impl
9            $(#[$attr])*
10            pub trait $trait_name<'ast> {
11                fn visit_block(&mut v, block: &'ast $($mut)? Block) {
12                    for stmt in & $($mut)? block.stmts {
13                        v.visit_stmt(stmt);
14                    }
15                }
16
17                fn visit_stmt(&mut v, stmt: &'ast $($mut)? Stmt) {
18                    match stmt {
19                        Stmt::Assembly(asm) => v.visit_stmt_asm(asm),
20                        Stmt::Block(block) => v.visit_block(block),
21                        Stmt::Break(brk) => v.visit_stmt_break(brk),
22                        Stmt::Continue(cont) => v.visit_stmt_continue(cont),
23                        Stmt::DoWhile(dowhile) => v.visit_stmt_dowhile(dowhile),
24                        Stmt::Emit(emit) => v.visit_stmt_emit(emit),
25                        Stmt::Expr(expr) => v.visit_expr(& $($mut)? expr.expr),
26                        Stmt::For(f) => v.visit_stmt_for(f),
27                        Stmt::If(ifstmt) => v.visit_stmt_if(ifstmt),
28                        Stmt::Return(ret) => v.visit_stmt_return(ret),
29                        Stmt::Revert(revert) => v.visit_stmt_revert(revert),
30                        Stmt::Try(try_stmt) => v.visit_stmt_try(try_stmt),
31                        Stmt::UncheckedBlock(ublock) => v.visit_unchecked_block(ublock),
32                        Stmt::VarDecl(vard) => v.visit_stmt_var_decl(vard),
33                        Stmt::While(w) => v.visit_stmt_while(w),
34                    }
35                }
36
37                fn visit_stmt_asm(&mut v, _i: &'ast $($mut)? StmtAssembly) {
38                    // nothing to do
39                }
40
41                fn visit_stmt_break(&mut v, _i: &'ast $($mut)? StmtBreak) {
42                    // nothing to do
43                }
44
45                fn visit_stmt_continue(&mut v, _i: &'ast $($mut)? StmtContinue) {
46                    // nothing to do
47                }
48
49                fn visit_stmt_dowhile(&mut v, stmt_dowhile: &'ast $($mut)? StmtDoWhile) {
50                    v.visit_expr(& $($mut)? stmt_dowhile.cond);
51                    v.visit_stmt(& $($mut)? stmt_dowhile.body);
52                }
53
54                fn visit_stmt_emit(&mut v, emit: &'ast $($mut)? StmtEmit) {
55                    v.visit_expr(& $($mut)? emit.expr);
56                }
57
58                fn visit_stmt_for(&mut v, stmt_for: &'ast $($mut)? StmtFor) {
59                    match & $($mut)? stmt_for.init {
60                        ForInitStmt::Expr(expr) => v.visit_expr(& $($mut)? expr.expr),
61                        ForInitStmt::VarDecl(vard) => v.visit_stmt_var_decl(vard),
62                        ForInitStmt::Empty(_) => {}
63                    }
64
65                    v.visit_stmt(& $($mut)? stmt_for.body);
66                    if let Some(cond) = & $($mut)? stmt_for.cond {
67                        v.visit_expr(cond);
68                    }
69                    if let Some(post) = & $($mut)? stmt_for.post {
70                        v.visit_expr(post);
71                    }
72                }
73
74                fn visit_stmt_if(&mut v, stmt_if: &'ast $($mut)? StmtIf) {
75                    v.visit_expr(& $($mut)? stmt_if.cond);
76                    v.visit_stmt(& $($mut)? stmt_if.then_branch);
77                    if let Some((_, stmt)) = & $($mut)? stmt_if.else_branch {
78                        v.visit_stmt(stmt);
79                    }
80                }
81
82                fn visit_stmt_return(&mut v, ret: &'ast $($mut)? StmtReturn) {
83                    if let Some(ret_expr) = & $($mut)? ret.expr {
84                        v.visit_expr(ret_expr);
85                    }
86                }
87
88                fn visit_stmt_revert(&mut v, rvert: &'ast $($mut)? StmtRevert) {
89                    v.visit_expr(& $($mut)? rvert.expr);
90                }
91
92                fn visit_stmt_try(&mut v, stmt_try: &'ast $($mut)? StmtTry) {
93                    v.visit_block(& $($mut)? stmt_try.block);
94                    v.visit_expr(& $($mut)? stmt_try.expr);
95
96                    for catch in & $($mut)? stmt_try.catch {
97                        v.visit_block(& $($mut)? catch.block);
98                        for iden in & $($mut)? catch.list {
99                            v.visit_variable_declaration(iden);
100                        }
101                    }
102                    if let Some(ret) = & $($mut)? stmt_try.returns {
103                        v.visit_parameter_list(& $($mut)? ret.returns);
104                    }
105                }
106
107                fn visit_unchecked_block(&mut v, ublock: &'ast $($mut)? UncheckedBlock) {
108                    v.visit_block(& $($mut)? ublock.block);
109                }
110
111                fn visit_stmt_var_decl(&mut v, stmt_var_decl: &'ast $($mut)? StmtVarDecl) {
112                    if let Some((_, expr)) = & $($mut)? stmt_var_decl.assignment {
113                        v.visit_expr(expr);
114                    }
115                    match & $($mut)? stmt_var_decl.declaration {
116                        VarDeclDecl::VarDecl(vard) => v.visit_variable_declaration(vard),
117                        VarDeclDecl::Tuple(tuple) => {
118                            for var_opt in & $($mut)? tuple.vars {
119                                if let Some(var_decl) = var_opt {
120                                    v.visit_variable_declaration(var_decl);
121                                }
122                            }
123                        }
124                    }
125                }
126
127                fn visit_stmt_while(&mut v, stmt_while: &'ast $($mut)? StmtWhile) {
128                    v.visit_expr(& $($mut)? stmt_while.cond);
129                    v.visit_stmt(& $($mut)? stmt_while.body);
130                }
131
132                fn visit_expr(&mut v, expr: &'ast $($mut)? Expr) {
133                    match expr {
134                        Expr::Array(array) => v.visit_expr_array(array),
135                        Expr::Binary(binary) => v.visit_expr_binary(binary),
136                        Expr::Call(call) => v.visit_expr_call(call),
137                        Expr::CallOptions(call_options) => v.visit_expr_call_options(call_options),
138                        Expr::Delete(delete) => v.visit_expr_delete(delete),
139                        Expr::Ident(ident) => v.visit_ident(ident),
140                        Expr::Index(index) => v.visit_expr_index(index),
141                        Expr::Lit(lit) => v.visit_lit(lit),
142                        Expr::LitDenominated(lit_denominated) => v.visit_lit_denominated(lit_denominated),
143                        Expr::Member(member) => v.visit_expr_member(member),
144                        Expr::New(new) => v.visit_expr_new(new),
145                        Expr::Payable(payable) => v.visit_expr_payable(payable),
146                        Expr::Postfix(postfix) => v.visit_expr_postfix(postfix),
147                        Expr::Ternary(ternary) => v.visit_expr_ternary(ternary),
148                        Expr::Tuple(tuple) => v.visit_expr_tuple(tuple),
149                        Expr::Type(typ) => v.visit_type(typ),
150                        Expr::TypeCall(type_call) => v.visit_expr_type_call(type_call),
151                        Expr::Unary(unary) => v.visit_expr_unary(unary),
152                    }
153                }
154
155                fn visit_expr_array(&mut v, i: &'ast $($mut)? ExprArray) {
156                    for expr in & $($mut)? i.elems {
157                        v.visit_expr(expr);
158                    }
159                }
160
161                fn visit_expr_binary(&mut v, i: &'ast $($mut)? ExprBinary) {
162                    v.visit_expr(& $($mut)? i.left);
163                    v.visit_expr(& $($mut)? i.right);
164                }
165
166                fn visit_expr_call(&mut v, i: &'ast $($mut)? ExprCall) {
167                    v.visit_expr(& $($mut)? i.expr);
168                    match & $($mut)? i.args.list {
169                        ArgListImpl::Unnamed(args) => {
170                            for arg in args {
171                                v.visit_expr(arg);
172                            }
173                        },
174                        ArgListImpl::Named(args) => {
175                            for arg in & $($mut)? args.list {
176                                v.visit_ident(& $($mut)? arg.name);
177                                v.visit_expr(& $($mut)? arg.arg);
178                            }
179                        },
180                    }
181                }
182
183                fn visit_expr_call_options(&mut v, i: &'ast $($mut)? ExprCallOptions) {
184                    v.visit_expr(& $($mut)? i.expr);
185                    for arg in & $($mut)? i.args.list {
186                        v.visit_ident(& $($mut)? arg.name);
187                        v.visit_expr(& $($mut)? arg.arg);
188                    }
189                }
190
191                fn visit_expr_delete(&mut v, i: &'ast $($mut)? ExprDelete) {
192                    v.visit_expr(& $($mut)? i.expr);
193                }
194
195                fn visit_expr_index(&mut v, i: &'ast $($mut)? ExprIndex) {
196                    v.visit_expr(& $($mut)? i.expr);
197
198                    if let Some(index) = & $($mut)? i.start {
199                        v.visit_expr(index);
200                    }
201                    if let Some(index) = & $($mut)? i.end {
202                        v.visit_expr(index);
203                    }
204                }
205
206                fn visit_lit(&mut v, i: &'ast $($mut)? Lit) {
207                    // nothing to do
208                }
209
210                fn visit_lit_denominated(&mut v, i: &'ast $($mut)? LitDenominated) {
211                    // nothing to do
212                }
213
214                fn visit_expr_member(&mut v, i: &'ast $($mut)? ExprMember) {
215                    v.visit_expr(& $($mut)? i.expr);
216                    v.visit_expr(& $($mut)? i.member);
217                }
218
219                fn visit_expr_new(&mut v, i: &'ast $($mut)? ExprNew) {
220                    v.visit_type(& $($mut)? i.ty);
221                }
222
223                fn visit_expr_payable(&mut v, i: &'ast $($mut)? ExprPayable) {
224                    match & $($mut)? i.args.list {
225                        ArgListImpl::Unnamed(exprs) => {
226                            for expr in exprs {
227                                v.visit_expr(expr);
228                            }
229                        }
230                        ArgListImpl::Named(named) => {
231                            for a in & $($mut)? named.list {
232                                v.visit_ident(& $($mut)? a.name);
233                                v.visit_expr(& $($mut)? a.arg);
234                            }
235                        }
236                    }
237                }
238
239                fn visit_expr_postfix(&mut v, i: &'ast $($mut)? ExprPostfix) {
240                    v.visit_expr(& $($mut)? i.expr);
241                }
242
243                fn visit_expr_ternary(&mut v, i: &'ast $($mut)? ExprTernary) {
244                    v.visit_expr(& $($mut)? i.cond);
245                    v.visit_expr(& $($mut)? i.if_true);
246                    v.visit_expr(& $($mut)? i.if_false);
247                }
248
249                fn visit_expr_tuple(&mut v, i: &'ast $($mut)? ExprTuple) {
250                    for expr in & $($mut)? i.elems {
251                        v.visit_expr(expr);
252                    }
253                }
254
255                fn visit_expr_type_call(&mut v, i: &'ast $($mut)? ExprTypeCall) {
256                    v.visit_type(& $($mut)? i.ty);
257                }
258
259                fn visit_expr_unary(&mut v, i: &'ast $($mut)? ExprUnary) {
260                    v.visit_expr(& $($mut)? i.expr);
261                }
262
263                fn visit_lit_str(&mut v, lit: &'ast $($mut)? LitStr) {
264                    // nothing to do
265                }
266
267                fn visit_ident(&mut v, ident: &'ast $($mut)? SolIdent) {
268                    // nothing to do
269                }
270
271                fn visit_path(&mut v, ident: &'ast $($mut)? SolPath) {
272                    // nothing to do
273                }
274
275                fn visit_type(&mut v, ty: &'ast $($mut)? Type) {
276                    match ty {
277                        Type::Address(..)
278                        | Type::Bool(_)
279                        | Type::Uint(..)
280                        | Type::Int(..)
281                        | Type::String(_)
282                        | Type::Bytes(_)
283                        | Type::FixedBytes(..) => {},
284                        Type::Array(TypeArray { ty, .. }) => v.visit_type(ty),
285                        Type::Tuple(TypeTuple { types, .. }) => {
286                            for ty in types {
287                                v.visit_type(ty);
288                            }
289                        },
290                        Type::Function(TypeFunction { arguments, returns, .. }) => {
291                            v.visit_parameter_list(arguments);
292                            if let Some(returns) = returns {
293                                v.visit_parameter_list(& $($mut)? returns.returns);
294                            }
295                        },
296                        Type::Mapping(TypeMapping { key, key_name, value, value_name, .. }) => {
297                            v.visit_type(key);
298                            if let Some(key_name) = key_name {
299                                v.visit_ident(key_name);
300                            }
301                            v.visit_type(value);
302                            if let Some(value_name) = value_name {
303                                v.visit_ident(value_name);
304                            }
305                        },
306                        Type::Custom(name) => v.visit_path(name),
307                    }
308                }
309
310                fn visit_variable_declaration(&mut v, var: &'ast $($mut)? VariableDeclaration) {
311                    v.visit_type(& $($mut)? var.ty);
312                    if let Some(name) = & $($mut)? var.name {
313                        v.visit_ident(name);
314                    }
315                }
316
317                fn visit_variable_definition(&mut v, var: &'ast $($mut)? VariableDefinition) {
318                    v.visit_type(& $($mut)? var.ty);
319                    v.visit_ident(& $($mut)? var.name);
320                }
321
322                fn visit_parameter_list(&mut v, params: &'ast $($mut)? ParameterList) {
323                    for param in params {
324                        v.visit_variable_declaration(param);
325                    }
326                }
327
328                fn visit_field_list(&mut v, params: &'ast $($mut)? FieldList) {
329                    for param in params {
330                        v.visit_variable_declaration(param);
331                    }
332                }
333
334                fn visit_file(&mut v, file: &'ast $($mut)? File) {
335                    for item in & $($mut)? file.items {
336                        v.visit_item(item);
337                    }
338                }
339
340                fn visit_item(&mut v, item: &'ast $($mut)? Item) {
341                    match item {
342                        Item::Contract(contract) => v.visit_item_contract(contract),
343                        Item::Enum(enumm) => v.visit_item_enum(enumm),
344                        Item::Error(error) => v.visit_item_error(error),
345                        Item::Event(event) => v.visit_item_event(event),
346                        Item::Function(function) => v.visit_item_function(function),
347                        Item::Import(import) => v.visit_import_directive(import),
348                        Item::Pragma(pragma) => v.visit_pragma_directive(pragma),
349                        Item::Struct(strukt) => v.visit_item_struct(strukt),
350                        Item::Udt(udt) => v.visit_item_udt(udt),
351                        Item::Using(using) => v.visit_using_directive(using),
352                        Item::Variable(variable) => v.visit_variable_definition(variable),
353                    }
354                }
355
356                fn visit_item_contract(&mut v, contract: &'ast $($mut)? ItemContract) {
357                    v.visit_ident(& $($mut)? contract.name);
358                    for item in & $($mut)? contract.body {
359                        v.visit_item(item);
360                    }
361                }
362
363                fn visit_item_enum(&mut v, enumm: &'ast $($mut)? ItemEnum) {
364                    v.visit_ident(& $($mut)? enumm.name);
365                    for Variant { ident, .. } in & $($mut)? enumm.variants {
366                        v.visit_ident(ident);
367                    }
368                }
369
370                fn visit_item_error(&mut v, error: &'ast $($mut)? ItemError) {
371                    v.visit_ident(& $($mut)? error.name);
372                    v.visit_parameter_list(& $($mut)? error.parameters);
373                }
374
375                fn visit_item_event(&mut v, event: &'ast $($mut)? ItemEvent) {
376                    v.visit_ident(& $($mut)? event.name);
377                    for EventParameter { name, ty, .. } in & $($mut)? event.parameters {
378                        v.visit_type(ty);
379                        if let Some(name) = name {
380                            v.visit_ident(name);
381                        }
382                    }
383                }
384
385                fn visit_item_function(&mut v, function: &'ast $($mut)? ItemFunction) {
386                    if let Some(name) = & $($mut)? function.name {
387                        v.visit_ident(name);
388                    }
389                    v.visit_parameter_list(& $($mut)? function.parameters);
390                    if let Some(returns) = & $($mut)? function.returns {
391                        v.visit_parameter_list(& $($mut)? returns.returns);
392                    }
393                    if let FunctionBody::Block(block) = & $($mut)? function.body {
394                        v.visit_block(block);
395                    }
396                }
397
398                fn visit_import_directive(&mut v, import: &'ast $($mut)? ImportDirective) {
399                    match & $($mut)? import.path {
400                        ImportPath::Plain(ImportPlain { path, alias }) => {
401                            v.visit_lit_str(path);
402                            if let Some(ImportAlias { alias, .. }) = alias {
403                                v.visit_ident(alias);
404                            }
405                        }
406                        ImportPath::Aliases(ImportAliases { imports, path, .. }) => {
407                            for (name, alias) in imports {
408                                v.visit_ident(name);
409                                if let Some(ImportAlias { alias, .. }) = alias {
410                                    v.visit_ident(alias);
411                                }
412                            }
413                            v.visit_lit_str(path);
414                        }
415                        ImportPath::Glob(ImportGlob { alias, path, .. }) => {
416                            if let Some(ImportAlias { alias, .. }) = alias {
417                                v.visit_ident(alias);
418                            }
419                            v.visit_lit_str(path);
420                        }
421                    }
422                }
423
424                fn visit_pragma_directive(&mut v, pragma: &'ast $($mut)? PragmaDirective) {
425                    // nothing to do
426                }
427
428                fn visit_item_struct(&mut v, strukt: &'ast $($mut)? ItemStruct) {
429                    v.visit_ident(& $($mut)? strukt.name);
430                    v.visit_field_list(& $($mut)? strukt.fields);
431                }
432
433                fn visit_item_udt(&mut v, udt: &'ast $($mut)? ItemUdt) {
434                    v.visit_ident(& $($mut)? udt.name);
435                    v.visit_type(& $($mut)? udt.ty);
436                }
437
438                fn visit_using_directive(&mut v, using: &'ast $($mut)? UsingDirective) {
439                    // nothing to do
440                }
441            }
442        }
443    };
444
445    (
446        @impl
447        $(#[$attr:meta])*
448        $vis:vis trait $trait_name:ident<'ast> {$(
449            $(#[$fn_attr:meta])*
450            fn $fn_name:ident(&mut $v:ident $(, $arg_name:ident : $arg_ty:ty)*) { $($impl:tt)* }
451        )*}
452    ) => {
453        $(#[$attr])*
454        $vis trait $trait_name<'ast> {$(
455            $(#[$fn_attr])*
456            fn $fn_name(&mut self $(, $arg_name: $arg_ty)*) { $fn_name(self $(, $arg_name)*) }
457        )*}
458
459        $(
460            $(#[$fn_attr])*
461            pub fn $fn_name<'ast, V: ?Sized + $trait_name<'ast>>($v: &mut V $(, $arg_name: $arg_ty)*) {
462                $($impl)*
463            }
464        )*
465    };
466}
467
468macro_rules! kw_enum {
469    (
470        $(#[$attr:meta])*
471        $vis:vis enum $name:ident {$(
472            $(#[$variant_attr:meta])*
473            $variant:ident(kw::$kw:ident)
474        ),+ $(,)?}
475    ) => {
476        $(#[$attr])*
477        #[derive(Clone, Copy)]
478        $vis enum $name {$(
479            #[doc = concat!("`", stringify!($kw), "`\n\n")]
480            $(#[$variant_attr])*
481            $variant($crate::kw::$kw),
482        )+}
483
484        impl std::cmp::PartialEq for $name {
485            #[inline]
486            fn eq(&self, other: &Self) -> bool {
487                std::mem::discriminant(self) == std::mem::discriminant(other)
488            }
489        }
490
491        impl std::cmp::Eq for $name {}
492
493        impl std::hash::Hash for $name {
494            #[inline]
495            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
496                std::hash::Hash::hash(&std::mem::discriminant(self), state)
497            }
498        }
499
500        impl std::fmt::Display for $name {
501            #[inline]
502            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
503                f.write_str(self.as_str())
504            }
505        }
506
507        impl std::fmt::Debug for $name {
508            #[inline]
509            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
510                f.write_str(self.as_debug_str())
511            }
512        }
513
514        impl ::syn::parse::Parse for $name {
515            fn parse(input: ::syn::parse::ParseStream<'_>) -> ::syn::Result<Self> {
516                let lookahead = input.lookahead1();
517                $(
518                    if lookahead.peek($crate::kw::$kw) {
519                        input.parse::<$crate::kw::$kw>().map(Self::$variant)
520                    } else
521                )+
522                {
523                    Err(lookahead.error())
524                }
525            }
526        }
527
528        impl $crate::Spanned for $name {
529            fn span(&self) -> ::proc_macro2::Span {
530                match self {$(
531                    Self::$variant(kw) => kw.span,
532                )+}
533            }
534
535            fn set_span(&mut self, span: ::proc_macro2::Span) {
536                match self {$(
537                    Self::$variant(kw) => kw.span = span,
538                )+}
539            }
540        }
541
542        impl $name {
543            ::paste::paste! {
544                $(
545                    #[doc = concat!("Creates a new `", stringify!($variant), "` keyword with the given `span`.")]
546                    #[inline]
547                    pub fn [<new_ $variant:snake>](span: ::proc_macro2::Span) -> Self {
548                        Self::$variant(kw::$kw(span))
549                    }
550                )+
551            }
552
553            pub fn parse_opt(input: ::syn::parse::ParseStream<'_>) -> ::syn::Result<Option<Self>> {
554                $(
555                    if input.peek($crate::kw::$kw) {
556                        input.parse::<$crate::kw::$kw>().map(|kw| Some(Self::$variant(kw)))
557                    } else
558                )+
559                {
560                    Ok(None)
561                }
562            }
563
564            pub fn peek(lookahead: &::syn::parse::Lookahead1<'_>) -> bool {
565                $( lookahead.peek($crate::kw::$kw) )||+
566            }
567
568            pub const fn as_str(self) -> &'static str {
569                match self {$(
570                    Self::$variant(_) => stringify!($kw),
571                )+}
572            }
573
574            pub const fn as_debug_str(self) -> &'static str {
575                match self {$(
576                    Self::$variant(_) => stringify!($variant),
577                )+}
578            }
579
580            ::paste::paste! {
581                $(
582                    #[doc = concat!("Returns true if `self` matches `Self::", stringify!($variant), "`.")]
583                    #[inline]
584                    pub const fn [<is_ $variant:snake>](self) -> bool {
585                        matches!(self, Self::$variant(_))
586                    }
587                )+
588            }
589        }
590    };
591}
592
593macro_rules! op_enum {
594    (@skip $($tt:tt)*) => {};
595    (@first $first:tt $($rest:tt)*) => { ::syn::Token![$first] };
596
597    (@peek $input:ident, $lookahead:ident, $a:tt) => {
598        $lookahead.peek(::syn::Token![$a])
599    };
600    // can't use `peek2` for `BinOp::Sar` (`>>>`) since the first token is 2 characters,
601    // so take it in as input
602    (@peek $input:ident, $lookahead:ident, $a:tt $b:tt $peek:ident) => {
603        $lookahead.peek(::syn::Token![$a])
604            && $input.$peek(::syn::Token![$b])
605    };
606
607    (
608        $(#[$attr:meta])*
609        $vis:vis enum $name:ident {$(
610            $(#[$variant_attr:meta])*
611            $variant:ident($($op:tt)+) $($peek:ident)?
612        ),+ $(,)?}
613    ) => {
614        $(#[$attr])*
615        #[derive(Clone, Copy)]
616        $vis enum $name {$(
617            #[doc = concat!("`", $(stringify!($op),)+ "`\n\n")]
618            $(#[$variant_attr])*
619            $variant($(::syn::Token![$op]),+),
620        )+}
621
622        impl std::cmp::PartialEq for $name {
623            #[inline]
624            fn eq(&self, other: &Self) -> bool {
625                std::mem::discriminant(self) == std::mem::discriminant(other)
626            }
627        }
628
629        impl std::cmp::Eq for $name {}
630
631        impl std::hash::Hash for $name {
632            #[inline]
633            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
634                std::hash::Hash::hash(&std::mem::discriminant(self), state)
635            }
636        }
637
638        impl std::fmt::Display for $name {
639            #[inline]
640            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
641                f.write_str(self.as_str())
642            }
643        }
644
645        impl std::fmt::Debug for $name {
646            #[inline]
647            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
648                f.write_str(self.as_debug_str())
649            }
650        }
651
652        impl ::syn::parse::Parse for $name {
653            fn parse(input: ::syn::parse::ParseStream<'_>) -> ::syn::Result<Self> {
654                let lookahead = input.lookahead1();
655                $(
656                    if op_enum!(@peek input, lookahead, $($op)+ $($peek)?) {
657                        Ok(Self::$variant(
658                            $(input.parse::<::syn::Token![$op]>()?),+
659                        ))
660                    } else
661                )+
662                {
663                    Err(lookahead.error())
664                }
665            }
666        }
667
668        impl $crate::Spanned for $name {
669            fn span(&self) -> ::proc_macro2::Span {
670                match self {$(
671                    Self::$variant(kw, ..) => kw.span(),
672                )+}
673            }
674
675            fn set_span(&mut self, span: ::proc_macro2::Span) {
676                match self {$(
677                    Self::$variant(kw, ..) => kw.set_span(span),
678                )+}
679            }
680        }
681
682        impl $name {
683            ::paste::paste! {
684                $(
685                    #[doc = concat!("Creates a new `", stringify!($variant), "` operator with the given `span`.")]
686                    #[inline]
687                    pub fn [<new_ $variant:snake>](span: ::proc_macro2::Span) -> Self {
688                        Self::$variant($(::syn::Token![$op](span)),+)
689                    }
690                )+
691            }
692
693            #[allow(unused_parens, unused_variables)]
694            pub fn peek(input: syn::parse::ParseStream<'_>, lookahead: &::syn::parse::Lookahead1<'_>) -> bool {
695                $(
696                    (op_enum!(@peek input, lookahead, $($op)+ $($peek)?))
697                )||+
698            }
699
700            pub const fn as_str(self) -> &'static str {
701                match self {$(
702                    Self::$variant(..) => concat!($(stringify!($op)),+),
703                )+}
704            }
705
706            pub const fn as_debug_str(self) -> &'static str {
707                match self {$(
708                    Self::$variant(..) => stringify!($variant),
709                )+}
710            }
711
712            ::paste::paste! {
713                $(
714                    #[doc = concat!("Returns true if `self` matches `Self::", stringify!($variant), "`.")]
715                    #[inline]
716                    pub const fn [<is_ $variant:snake>](self) -> bool {
717                        matches!(self, Self::$variant(..))
718                    }
719                )+
720            }
721        }
722    };
723}
724
725macro_rules! derive_parse {
726    ($($t:ty),+ $(,)?) => {$(
727        impl Parse for $t {
728            fn parse(input: ParseStream<'_>) -> Result<Self> {
729                <Self as $crate::utils::ParseNested>::parse_nested(
730                    input.parse()?,
731                    input,
732                )
733            }
734        }
735    )+};
736}
737
738macro_rules! debug {
739    ($($t:tt)*) => {
740        if $crate::DEBUG {
741            eprintln!($($t)*)
742        }
743    };
744}