fayalite/crates/fayalite-proc-macros-impl/src/process_cfg.rs

2528 lines
46 KiB
Rust

// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{Cfg, CfgAttr, Cfgs, Errors};
use proc_macro2::Ident;
use std::{collections::VecDeque, marker::PhantomData};
use syn::{
punctuated::{Pair, Punctuated},
Token,
};
struct State<P: Phase> {
cfgs: Cfgs<P::CfgsValue>,
errors: Errors,
_phantom: PhantomData<P>,
}
impl<P: Phase> State<P> {
#[must_use]
fn eval_cfg(&mut self, cfg: Cfg) -> bool {
struct MyDispatch<'a> {
cfg: Cfg,
_phantom: PhantomData<&'a ()>,
}
impl<'a> PhaseDispatch for MyDispatch<'a> {
type Args<P: Phase> = &'a mut State<P>;
type Output<P: Phase> = bool;
fn dispatch_collect(
self,
args: Self::Args<CollectCfgsPhase>,
) -> Self::Output<CollectCfgsPhase> {
args.cfgs.insert_cfg(self.cfg, ());
true
}
fn dispatch_process(
self,
args: Self::Args<ProcessCfgsPhase>,
) -> Self::Output<ProcessCfgsPhase> {
if let Some(&retval) = args.cfgs.cfgs_map.get(&self.cfg) {
retval
} else {
args.errors.error(self.cfg, "unrecognized cfg -- cfg wasn't evaluated when running `__cfg_expansion_helper!`");
true
}
}
}
P::dispatch(
MyDispatch {
cfg,
_phantom: PhantomData,
},
self,
)
}
#[must_use]
fn eval_cfgs(
&mut self,
mut attrs: Vec<syn::Attribute>,
) -> Option<Output<Vec<syn::Attribute>, P>> {
let mut queue = VecDeque::from(attrs);
attrs = Vec::with_capacity(queue.len()); // cfg_attr is rare, and cfg can't increase length
while let Some(attr) = queue.pop_front() {
if attr.path().is_ident("cfg") {
if let Some(cfg) = self.errors.ok(Cfg::parse_meta(&attr.meta)) {
if !self.eval_cfg(cfg) {
return None;
}
continue;
}
} else if attr.path().is_ident("cfg_attr") {
if let Some(cfg_attr) = self.errors.ok(CfgAttr::parse_meta(&attr.meta)) {
if self.eval_cfg(cfg_attr.to_cfg()) {
// push onto queue since cfg_attr(<cond1>, cfg_attr(<cond2>, <attr>)) is valid
for meta in cfg_attr.attrs {
queue.push_front(syn::Attribute {
pound_token: attr.pound_token,
style: attr.style,
bracket_token: attr.bracket_token,
meta,
});
}
}
continue;
}
}
attrs.push(attr);
}
Some(Output::new(attrs))
}
fn process_qself_and_path(
&mut self,
qself: Option<syn::QSelf>,
path: syn::Path,
) -> Option<(Output<Option<syn::QSelf>, P>, Output<syn::Path, P>)> {
let qself = if let Some(syn::QSelf {
lt_token,
ty,
position,
as_token,
gt_token,
}) = qself
{
ty.process(self)?.map(|ty| {
Some(syn::QSelf {
lt_token,
ty,
position,
as_token,
gt_token,
})
})
} else {
Output::new(None)
};
let syn::Path {
leading_colon,
segments,
} = path;
// path segments don't get removed
let path = segments.process(self)?.map(|segments| syn::Path {
leading_colon,
segments,
});
Some((qself, path))
}
}
trait PhaseDispatch {
type Args<P: Phase>;
type Output<P: Phase>;
fn dispatch_collect(self, args: Self::Args<CollectCfgsPhase>)
-> Self::Output<CollectCfgsPhase>;
fn dispatch_process(self, args: Self::Args<ProcessCfgsPhase>)
-> Self::Output<ProcessCfgsPhase>;
}
trait Phase: Sized + 'static {
type Output<T>;
type CfgsValue;
fn output_new<T>(v: T) -> Output<T, Self>;
fn output_map<T, U, F: FnOnce(T) -> U>(v: Output<T, Self>, f: F) -> Output<U, Self>;
fn output_zip<T, U>(t: Output<T, Self>, u: Output<U, Self>) -> Output<(T, U), Self>;
fn dispatch<D: PhaseDispatch>(d: D, args: D::Args<Self>) -> D::Output<Self>;
}
struct CollectCfgsPhase;
impl Phase for CollectCfgsPhase {
type Output<T> = ();
type CfgsValue = ();
fn output_new<T>(_v: T) -> Output<T, Self> {
Output(())
}
fn output_map<T, U, F: FnOnce(T) -> U>(_v: Output<T, Self>, _f: F) -> Output<U, Self> {
Output(())
}
fn output_zip<T, U>(_t: Output<T, Self>, _u: Output<U, Self>) -> Output<(T, U), Self> {
Output(())
}
fn dispatch<D: PhaseDispatch>(d: D, args: D::Args<Self>) -> D::Output<Self> {
d.dispatch_collect(args)
}
}
struct ProcessCfgsPhase;
impl Phase for ProcessCfgsPhase {
type Output<T> = T;
type CfgsValue = bool;
fn output_new<T>(v: T) -> Output<T, Self> {
Output(v)
}
fn output_map<T, U, F: FnOnce(T) -> U>(v: Output<T, Self>, f: F) -> Output<U, Self> {
Output(f(v.0))
}
fn output_zip<T, U>(t: Output<T, Self>, u: Output<U, Self>) -> Output<(T, U), Self> {
Output((t.0, u.0))
}
fn dispatch<D: PhaseDispatch>(d: D, args: D::Args<Self>) -> D::Output<Self> {
d.dispatch_process(args)
}
}
struct Output<T, P: Phase>(P::Output<T>);
trait OutputZip<P: Phase>: Sized {
type Output;
fn zip(self) -> Output<Self::Output, P>;
fn call<R, F: FnOnce(Self::Output) -> R>(self, f: F) -> Output<R, P> {
self.zip().map(f)
}
}
impl<P: Phase> OutputZip<P> for () {
type Output = ();
fn zip(self) -> Output<Self::Output, P> {
Output::new(())
}
}
impl<P: Phase, T> OutputZip<P> for (Output<T, P>,) {
type Output = (T,);
fn zip(self) -> Output<Self::Output, P> {
self.0.map(|v| (v,))
}
}
macro_rules! impl_zip {
($first_arg:ident: $first_T:ident, $($arg:ident: $T:ident),* $(,)?) => {
impl_zip!(@step [], [($first_arg: $first_T) $(($arg: $T))*], (),);
};
(
@impl($first_arg:tt,),
$tuple_pat:tt,
) => {};
(
@impl(($first_arg:ident: $first_T:ident),
$(($arg:ident: $T:ident),)*),
$tuple_pat:tt,
) => {
impl<$first_T, $($T,)* P: Phase> OutputZip<P> for (Output<$first_T, P>, $(Output<$T, P>),*) {
type Output = ($first_T, $($T),*);
fn zip(self) -> Output<($first_T, $($T),*), P> {
let (tuples, $($arg),*) = self;
$(let tuples = P::output_zip(tuples, $arg);)*
tuples.map(|$tuple_pat| ($first_arg, $($arg),*))
}
}
};
(
@step [$($cur:tt)*],
[],
$tuple_pat:tt,
) => {};
(
@step [$($cur:tt)*],
[($next_arg:ident: $next_T:ident) $($rest:tt)*],
(),
) => {
impl_zip!(@impl($($cur,)* ($next_arg: $next_T),), $next_arg,);
impl_zip!(@step [$($cur)* ($next_arg: $next_T)], [$($rest)*], $next_arg,);
};
(
@step [$($cur:tt)*],
[($next_arg:ident: $next_T:ident) $($rest:tt)*],
$tuple_pat:tt,
) => {
impl_zip!(@impl($($cur,)* ($next_arg: $next_T),), ($tuple_pat, $next_arg),);
impl_zip!(@step [$($cur)* ($next_arg: $next_T)], [$($rest)*], ($tuple_pat, $next_arg),);
};
}
impl_zip!(t0: T0, t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7, t8: T8, t9: T9, t10: T10, t11: T11);
impl<T, P: Phase> Copy for Output<T, P> where P::Output<T>: Copy {}
impl<T, P: Phase> Clone for Output<T, P>
where
P::Output<T>: Clone,
{
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T, P: Phase> Output<T, P> {
fn new(v: T) -> Self {
P::output_new(v)
}
fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Output<U, P> {
P::output_map(self, f)
}
}
trait Process<P: Phase>: Sized {
#[must_use]
fn process(self, state: &mut State<P>) -> Option<Output<Self, P>>;
}
impl<P: Phase> Process<P> for syn::Item {
fn process(self, _state: &mut State<P>) -> Option<Output<Self, P>> {
// don't recurse into items
Some(Output::new(self))
}
}
impl<P: Phase> Process<P> for Vec<syn::Attribute> {
fn process(self, state: &mut State<P>) -> Option<Output<Self, P>> {
state.eval_cfgs(self)
}
}
impl<T: Process<P>, P: Phase> Process<P> for Box<T> {
fn process(self, state: &mut State<P>) -> Option<Output<Self, P>> {
Some(T::process(*self, state)?.map(Box::new))
}
}
trait ProcessVecElement {
const REMOVE_ELEMENTS: bool;
}
impl ProcessVecElement for syn::Arm {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessVecElement for syn::Stmt {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessVecElement for syn::ForeignItem {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessVecElement for syn::ImplItem {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessVecElement for syn::Item {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessVecElement for syn::TraitItem {
const REMOVE_ELEMENTS: bool = true;
}
impl<T: Process<P> + ProcessVecElement, P: Phase> Process<P> for Vec<T> {
fn process(self, state: &mut State<P>) -> Option<Output<Self, P>> {
let mut output = Output::new(Vec::new());
for value in self {
if let Some(value) = value.process(state) {
output = (output, value).call(|(mut output, value)| {
output.push(value);
output
});
} else if !T::REMOVE_ELEMENTS {
return None;
}
}
Some(output)
}
}
trait ProcessOption {
/// if a configured-off value causes this value to be `None` instead of propagating the configuring-off
const REMOVE_VALUE: bool;
}
impl ProcessOption for syn::Abi {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for syn::Block {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for syn::WhereClause {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for syn::Expr {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for syn::Type {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for Box<syn::Expr> {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for syn::AngleBracketedGenericArguments {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for syn::ImplRestriction {
const REMOVE_VALUE: bool = false;
}
impl ProcessOption for syn::BoundLifetimes {
const REMOVE_VALUE: bool = false;
}
impl ProcessOption for (Token![=], syn::Expr) {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for (Token![=], syn::Type) {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for (Token![if], Box<syn::Expr>) {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for (Token![else], Box<syn::Expr>) {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for (Token![&], Option<syn::Lifetime>) {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for (Token![as], Ident) {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for (Ident, Token![:]) {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for (Option<Token![!]>, syn::Path, Token![for]) {
const REMOVE_VALUE: bool = false;
}
impl ProcessOption for syn::BareVariadic {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for syn::Variadic {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for syn::LocalInit {
const REMOVE_VALUE: bool = false;
}
impl ProcessOption for syn::Label {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for syn::PatRest {
const REMOVE_VALUE: bool = true;
}
impl ProcessOption for (Box<syn::Pat>, Token![:]) {
const REMOVE_VALUE: bool = false;
}
impl ProcessOption for (Token![@], Box<syn::Pat>) {
const REMOVE_VALUE: bool = false;
}
impl ProcessOption for (syn::token::Brace, Vec<syn::Item>) {
const REMOVE_VALUE: bool = false;
}
impl<T: Process<P> + ProcessOption, P: Phase> Process<P> for Option<T> {
fn process(self, state: &mut State<P>) -> Option<Output<Self, P>> {
if let Some(this) = self {
match this.process(state) {
Some(v) => Some(v.map(Some)),
None => {
if T::REMOVE_VALUE {
Some(Output::new(None))
} else {
None
}
}
}
} else {
Some(Output::new(None))
}
}
}
trait ProcessPunctuatedElement {
const REMOVE_ELEMENTS: bool;
}
impl<T: Process<P> + ProcessPunctuatedElement, P: Phase, Punct: Default> Process<P>
for Punctuated<T, Punct>
{
fn process(self, state: &mut State<P>) -> Option<Output<Self, P>> {
let mut output = Output::new(Punctuated::<T, Punct>::new());
for pair in self.into_pairs() {
let (value, punct) = pair.into_tuple();
if let Some(value) = value.process(state) {
output = (output, value).call(|(mut output, value)| {
output.extend([Pair::new(value, punct)]);
output
});
} else if !T::REMOVE_ELEMENTS {
return None;
}
}
Some(output)
}
}
impl ProcessPunctuatedElement for syn::PathSegment {
const REMOVE_ELEMENTS: bool = false;
}
impl ProcessPunctuatedElement for syn::Type {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessPunctuatedElement for syn::Expr {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessPunctuatedElement for syn::Pat {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessPunctuatedElement for syn::CapturedParam {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessPunctuatedElement for syn::GenericArgument {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessPunctuatedElement for syn::GenericParam {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessPunctuatedElement for syn::Lifetime {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessPunctuatedElement for syn::WherePredicate {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessPunctuatedElement for syn::Variant {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessPunctuatedElement for syn::FnArg {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessPunctuatedElement for syn::BareFnArg {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessPunctuatedElement for syn::TypeParamBound {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessPunctuatedElement for syn::FieldValue {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessPunctuatedElement for syn::Field {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessPunctuatedElement for syn::FieldPat {
const REMOVE_ELEMENTS: bool = true;
}
impl ProcessPunctuatedElement for syn::UseTree {
const REMOVE_ELEMENTS: bool = true;
}
impl<T: Process<P>, U: Process<P>, P: Phase> Process<P> for (T, U) {
fn process(self, state: &mut State<P>) -> Option<Output<Self, P>> {
let (t, u) = self;
let t = t.process(state)?;
let u = u.process(state)?;
Some((t, u).zip())
}
}
impl<T: Process<P>, U: Process<P>, V: Process<P>, P: Phase> Process<P> for (T, U, V) {
fn process(self, state: &mut State<P>) -> Option<Output<Self, P>> {
let (t, u, v) = self;
let t = t.process(state)?;
let u = u.process(state)?;
let v = v.process(state)?;
Some((t, u, v).zip())
}
}
macro_rules! process_no_op {
($ty:ty) => {
impl<P: Phase> Process<P> for $ty {
fn process(self, _state: &mut State<P>) -> Option<Output<Self, P>> {
Some(Output::new(self))
}
}
impl ProcessOption for $ty {
const REMOVE_VALUE: bool = false;
}
};
}
process_no_op!(Token![Self]);
process_no_op!(Token![abstract]);
process_no_op!(Token![as]);
process_no_op!(Token![async]);
process_no_op!(Token![auto]);
process_no_op!(Token![await]);
process_no_op!(Token![become]);
process_no_op!(Token![box]);
process_no_op!(Token![break]);
process_no_op!(Token![const]);
process_no_op!(Token![continue]);
process_no_op!(Token![crate]);
process_no_op!(Token![default]);
process_no_op!(Token![do]);
process_no_op!(Token![dyn]);
process_no_op!(Token![else]);
process_no_op!(Token![enum]);
process_no_op!(Token![extern]);
process_no_op!(Token![final]);
process_no_op!(Token![fn]);
process_no_op!(Token![for]);
process_no_op!(Token![if]);
process_no_op!(Token![impl]);
process_no_op!(Token![in]);
process_no_op!(Token![let]);
process_no_op!(Token![loop]);
process_no_op!(Token![macro]);
process_no_op!(Token![match]);
process_no_op!(Token![mod]);
process_no_op!(Token![move]);
process_no_op!(Token![mut]);
process_no_op!(Token![override]);
process_no_op!(Token![priv]);
process_no_op!(Token![pub]);
process_no_op!(Token![raw]);
process_no_op!(Token![ref]);
process_no_op!(Token![return]);
process_no_op!(Token![self]);
process_no_op!(Token![static]);
process_no_op!(Token![struct]);
process_no_op!(Token![super]);
process_no_op!(Token![trait]);
process_no_op!(Token![try]);
process_no_op!(Token![type]);
process_no_op!(Token![typeof]);
process_no_op!(Token![union]);
process_no_op!(Token![unsafe]);
process_no_op!(Token![unsized]);
process_no_op!(Token![use]);
process_no_op!(Token![virtual]);
process_no_op!(Token![where]);
process_no_op!(Token![while]);
process_no_op!(Token![yield]);
process_no_op!(Token![!]);
process_no_op!(Token![!=]);
process_no_op!(Token![#]);
process_no_op!(Token![$]);
process_no_op!(Token![%]);
process_no_op!(Token![%=]);
process_no_op!(Token![&]);
process_no_op!(Token![&&]);
process_no_op!(Token![&=]);
process_no_op!(Token![*]);
process_no_op!(Token![*=]);
process_no_op!(Token![+]);
process_no_op!(Token![+=]);
process_no_op!(Token![,]);
process_no_op!(Token![-]);
process_no_op!(Token![-=]);
process_no_op!(Token![->]);
process_no_op!(Token![.]);
process_no_op!(Token![..]);
process_no_op!(Token![...]);
process_no_op!(Token![..=]);
process_no_op!(Token![/]);
process_no_op!(Token![/=]);
process_no_op!(Token![:]);
process_no_op!(Token![::]);
process_no_op!(Token![;]);
process_no_op!(Token![<]);
process_no_op!(Token![<-]);
process_no_op!(Token![<<]);
process_no_op!(Token![<<=]);
process_no_op!(Token![<=]);
process_no_op!(Token![=]);
process_no_op!(Token![==]);
process_no_op!(Token![=>]);
process_no_op!(Token![>]);
process_no_op!(Token![>=]);
process_no_op!(Token![>>]);
process_no_op!(Token![>>=]);
process_no_op!(Token![?]);
process_no_op!(Token![@]);
process_no_op!(Token![^]);
process_no_op!(Token![^=]);
process_no_op!(Token![_]);
process_no_op!(Token![|]);
process_no_op!(Token![|=]);
process_no_op!(Token![||]);
process_no_op!(Token![~]);
process_no_op!(syn::token::Brace);
process_no_op!(syn::token::Bracket);
process_no_op!(syn::token::Paren);
process_no_op!(syn::token::Group);
process_no_op!(Ident);
process_no_op!(syn::Index);
process_no_op!(syn::Lifetime);
process_no_op!(syn::LitBool);
process_no_op!(syn::LitByte);
process_no_op!(syn::LitByteStr);
process_no_op!(syn::LitChar);
process_no_op!(syn::LitCStr);
process_no_op!(syn::LitFloat);
process_no_op!(syn::LitInt);
process_no_op!(syn::LitStr);
process_no_op!(proc_macro2::TokenStream);
process_no_op!(proc_macro2::Literal);
macro_rules! process_struct {
($ty:path {
$($field:ident,)*
}) => {
impl<P: Phase> Process<P> for $ty {
fn process(self, state: &mut State<P>) -> Option<Output<Self, P>> {
let Self {
$($field,)*
} = self;
$(let $field = $field.process(state)?;)*
Some(($($field,)*).call(|($($field,)*)| Self {
$($field,)*
}))
}
}
};
($ty:path {
$($fields_before:ident,)*
#[qself]
$qself:ident,
$path:ident,
$($fields_after:ident,)*
}) => {
impl<P: Phase> Process<P> for $ty {
fn process(self, state: &mut State<P>) -> Option<Output<Self, P>> {
let Self {
$($fields_before,)*
$qself,
$path,
$($fields_after,)*
} = self;
$(let $fields_before = $fields_before.process(state)?;)*
let ($qself, $path) = state.process_qself_and_path($qself, $path)?;
$(let $fields_after = $fields_after.process(state)?;)*
Some((
$($fields_before,)*
$qself,
$path,
$($fields_after,)*
).call(|(
$($fields_before,)*
$qself,
$path,
$($fields_after,)*
)| Self {
$($fields_before,)*
$qself,
$path,
$($fields_after,)*
}))
}
}
};
}
process_struct! {
syn::Abi {
extern_token,
name,
}
}
process_struct! {
syn::AngleBracketedGenericArguments {
colon2_token,
lt_token,
args,
gt_token,
}
}
process_struct! {
syn::Arm {
attrs,
pat,
guard,
fat_arrow_token,
body,
comma,
}
}
process_struct! {
syn::AssocConst {
ident,
generics,
eq_token,
value,
}
}
process_struct! {
syn::AssocType {
ident,
generics,
eq_token,
ty,
}
}
process_struct! {
syn::BareFnArg {
attrs,
name,
ty,
}
}
process_struct! {
syn::BareVariadic {
attrs,
name,
dots,
comma,
}
}
process_struct! {
syn::Block {
brace_token,
stmts,
}
}
process_struct! {
syn::BoundLifetimes {
for_token,
lt_token,
lifetimes,
gt_token,
}
}
process_struct! {
syn::ConstParam {
attrs,
const_token,
ident,
colon_token,
ty,
eq_token,
default,
}
}
process_struct! {
syn::Constraint {
ident,
generics,
colon_token,
bounds,
}
}
process_struct! {
syn::DataEnum {
enum_token,
brace_token,
variants,
}
}
process_struct! {
syn::DataStruct {
struct_token,
fields,
semi_token,
}
}
process_struct! {
syn::DataUnion {
union_token,
fields,
}
}
process_struct! {
syn::DeriveInput {
attrs,
vis,
ident,
generics,
data,
}
}
process_struct! {
syn::ExprArray {
attrs,
bracket_token,
elems,
}
}
process_struct! {
syn::ExprAssign {
attrs,
left,
eq_token,
right,
}
}
process_struct! {
syn::ExprAsync {
attrs,
async_token,
capture,
block,
}
}
process_struct! {
syn::ExprAwait {
attrs,
base,
dot_token,
await_token,
}
}
process_struct! {
syn::ExprBinary {
attrs,
left,
op,
right,
}
}
process_struct! {
syn::ExprBlock {
attrs,
label,
block,
}
}
process_struct! {
syn::ExprBreak {
attrs,
break_token,
label,
expr,
}
}
process_struct! {
syn::ExprCall {
attrs,
func,
paren_token,
args,
}
}
process_struct! {
syn::ExprCast {
attrs,
expr,
as_token,
ty,
}
}
process_struct! {
syn::ExprClosure {
attrs,
lifetimes,
constness,
movability,
asyncness,
capture,
or1_token,
inputs,
or2_token,
output,
body,
}
}
process_struct! {
syn::ExprConst {
attrs,
const_token,
block,
}
}
process_struct! {
syn::ExprContinue {
attrs,
continue_token,
label,
}
}
process_struct! {
syn::ExprField {
attrs,
base,
dot_token,
member,
}
}
process_struct! {
syn::ExprForLoop {
attrs,
label,
for_token,
pat,
in_token,
expr,
body,
}
}
process_struct! {
syn::ExprGroup {
attrs,
group_token,
expr,
}
}
process_struct! {
syn::ExprIf {
attrs,
if_token,
cond,
then_branch,
else_branch,
}
}
process_struct! {
syn::ExprIndex {
attrs,
expr,
bracket_token,
index,
}
}
process_struct! {
syn::ExprInfer {
attrs,
underscore_token,
}
}
process_struct! {
syn::ExprLet {
attrs,
let_token,
pat,
eq_token,
expr,
}
}
process_struct! {
syn::ExprLit {
attrs,
lit,
}
}
process_struct! {
syn::ExprLoop {
attrs,
label,
loop_token,
body,
}
}
process_struct! {
syn::ExprMacro {
attrs,
mac,
}
}
process_struct! {
syn::ExprMatch {
attrs,
match_token,
expr,
brace_token,
arms,
}
}
process_struct! {
syn::ExprMethodCall {
attrs,
receiver,
dot_token,
method,
turbofish,
paren_token,
args,
}
}
process_struct! {
syn::ExprParen {
attrs,
paren_token,
expr,
}
}
process_struct! {
syn::ExprPath {
attrs,
#[qself]
qself,
path,
}
}
process_struct! {
syn::ExprRange {
attrs,
start,
limits,
end,
}
}
process_struct! {
syn::ExprRawAddr {
attrs,
and_token,
raw,
mutability,
expr,
}
}
process_struct! {
syn::ExprReference {
attrs,
and_token,
mutability,
expr,
}
}
process_struct! {
syn::ExprRepeat {
attrs,
bracket_token,
expr,
semi_token,
len,
}
}
process_struct! {
syn::ExprReturn {
attrs,
return_token,
expr,
}
}
process_struct! {
syn::ExprStruct {
attrs,
#[qself]
qself,
path,
brace_token,
fields,
dot2_token,
rest,
}
}
process_struct! {
syn::ExprTry {
attrs,
expr,
question_token,
}
}
process_struct! {
syn::ExprTryBlock {
attrs,
try_token,
block,
}
}
process_struct! {
syn::ExprTuple {
attrs,
paren_token,
elems,
}
}
process_struct! {
syn::ExprUnary {
attrs,
op,
expr,
}
}
process_struct! {
syn::ExprUnsafe {
attrs,
unsafe_token,
block,
}
}
process_struct! {
syn::ExprWhile {
attrs,
label,
while_token,
cond,
body,
}
}
process_struct! {
syn::ExprYield {
attrs,
yield_token,
expr,
}
}
process_struct! {
syn::Field {
attrs,
vis,
mutability,
ident,
colon_token,
ty,
}
}
process_struct! {
syn::FieldPat {
attrs,
member,
colon_token,
pat,
}
}
process_struct! {
syn::FieldValue {
attrs,
member,
colon_token,
expr,
}
}
process_struct! {
syn::FieldsNamed {
brace_token,
named,
}
}
process_struct! {
syn::FieldsUnnamed {
paren_token,
unnamed,
}
}
process_struct! {
syn::ForeignItemFn {
attrs,
vis,
sig,
semi_token,
}
}
process_struct! {
syn::ForeignItemMacro {
attrs,
mac,
semi_token,
}
}
process_struct! {
syn::ForeignItemStatic {
attrs,
vis,
static_token,
mutability,
ident,
colon_token,
ty,
semi_token,
}
}
process_struct! {
syn::ForeignItemType {
attrs,
vis,
type_token,
ident,
generics,
semi_token,
}
}
process_struct! {
syn::Generics {
lt_token,
params,
gt_token,
where_clause,
}
}
process_struct! {
syn::ImplItemConst {
attrs,
vis,
defaultness,
const_token,
ident,
generics,
colon_token,
ty,
eq_token,
expr,
semi_token,
}
}
process_struct! {
syn::ImplItemFn {
attrs,
vis,
defaultness,
sig,
block,
}
}
process_struct! {
syn::ImplItemMacro {
attrs,
mac,
semi_token,
}
}
process_struct! {
syn::ImplItemType {
attrs,
vis,
defaultness,
type_token,
ident,
generics,
eq_token,
ty,
semi_token,
}
}
process_struct! {
syn::ItemConst {
attrs,
vis,
const_token,
ident,
generics,
colon_token,
ty,
eq_token,
expr,
semi_token,
}
}
process_struct! {
syn::ItemEnum {
attrs,
vis,
enum_token,
ident,
generics,
brace_token,
variants,
}
}
process_struct! {
syn::ItemExternCrate {
attrs,
vis,
extern_token,
crate_token,
ident,
rename,
semi_token,
}
}
process_struct! {
syn::ItemFn {
attrs,
vis,
sig,
block,
}
}
process_struct! {
syn::ItemForeignMod {
attrs,
unsafety,
abi,
brace_token,
items,
}
}
process_struct! {
syn::ItemImpl {
attrs,
defaultness,
unsafety,
impl_token,
generics,
trait_,
self_ty,
brace_token,
items,
}
}
process_struct! {
syn::ItemMacro {
attrs,
ident,
mac,
semi_token,
}
}
process_struct! {
syn::ItemMod {
attrs,
vis,
unsafety,
mod_token,
ident,
content,
semi,
}
}
process_struct! {
syn::ItemStatic {
attrs,
vis,
static_token,
mutability,
ident,
colon_token,
ty,
eq_token,
expr,
semi_token,
}
}
process_struct! {
syn::ItemStruct {
attrs,
vis,
struct_token,
ident,
generics,
fields,
semi_token,
}
}
process_struct! {
syn::ItemTrait {
attrs,
vis,
unsafety,
auto_token,
restriction,
trait_token,
ident,
generics,
colon_token,
supertraits,
brace_token,
items,
}
}
process_struct! {
syn::ItemTraitAlias {
attrs,
vis,
trait_token,
ident,
generics,
eq_token,
bounds,
semi_token,
}
}
process_struct! {
syn::ItemType {
attrs,
vis,
type_token,
ident,
generics,
eq_token,
ty,
semi_token,
}
}
process_struct! {
syn::ItemUnion {
attrs,
vis,
union_token,
ident,
generics,
fields,
}
}
process_struct! {
syn::ItemUse {
attrs,
vis,
use_token,
leading_colon,
tree,
semi_token,
}
}
process_struct! {
syn::Label {
name,
colon_token,
}
}
process_struct! {
syn::LifetimeParam {
attrs,
lifetime,
colon_token,
bounds,
}
}
process_struct! {
syn::Local {
attrs,
let_token,
pat,
init,
semi_token,
}
}
process_struct! {
syn::LocalInit {
eq_token,
expr,
diverge,
}
}
process_struct! {
syn::Macro {
path,
bang_token,
delimiter,
tokens,
}
}
process_struct! {
syn::MetaList {
path,
delimiter,
tokens,
}
}
process_struct! {
syn::MetaNameValue {
path,
eq_token,
value,
}
}
process_struct! {
syn::ParenthesizedGenericArguments {
paren_token,
inputs,
output,
}
}
process_struct! {
syn::PatIdent {
attrs,
by_ref,
mutability,
ident,
subpat,
}
}
process_struct! {
syn::PatOr {
attrs,
leading_vert,
cases,
}
}
process_struct! {
syn::PatParen {
attrs,
paren_token,
pat,
}
}
process_struct! {
syn::PatReference {
attrs,
and_token,
mutability,
pat,
}
}
process_struct! {
syn::PatRest {
attrs,
dot2_token,
}
}
process_struct! {
syn::PatSlice {
attrs,
bracket_token,
elems,
}
}
process_struct! {
syn::PatStruct {
attrs,
#[qself]
qself,
path,
brace_token,
fields,
rest,
}
}
process_struct! {
syn::PatTuple {
attrs,
paren_token,
elems,
}
}
process_struct! {
syn::PatTupleStruct {
attrs,
#[qself]
qself,
path,
paren_token,
elems,
}
}
process_struct! {
syn::PatType {
attrs,
pat,
colon_token,
ty,
}
}
process_struct! {
syn::PatWild {
attrs,
underscore_token,
}
}
process_struct! {
syn::Path {
leading_colon,
segments,
}
}
process_struct! {
syn::PathSegment {
ident,
arguments,
}
}
process_struct! {
syn::PreciseCapture {
use_token,
lt_token,
params,
gt_token,
}
}
process_struct! {
syn::PredicateLifetime {
lifetime,
colon_token,
bounds,
}
}
process_struct! {
syn::PredicateType {
lifetimes,
bounded_ty,
colon_token,
bounds,
}
}
process_struct! {
syn::Receiver {
attrs,
reference,
mutability,
self_token,
colon_token,
ty,
}
}
process_struct! {
syn::Signature {
constness,
asyncness,
unsafety,
abi,
fn_token,
ident,
generics,
paren_token,
inputs,
variadic,
output,
}
}
process_struct! {
syn::StmtMacro {
attrs,
mac,
semi_token,
}
}
process_struct! {
syn::TraitBound {
paren_token,
modifier,
lifetimes,
path,
}
}
process_struct! {
syn::TraitItemConst {
attrs,
const_token,
ident,
generics,
colon_token,
ty,
default,
semi_token,
}
}
process_struct! {
syn::TraitItemFn {
attrs,
sig,
default,
semi_token,
}
}
process_struct! {
syn::TraitItemMacro {
attrs,
mac,
semi_token,
}
}
process_struct! {
syn::TraitItemType {
attrs,
type_token,
ident,
generics,
colon_token,
bounds,
default,
semi_token,
}
}
process_struct! {
syn::TypeArray {
bracket_token,
elem,
semi_token,
len,
}
}
process_struct! {
syn::TypeBareFn {
lifetimes,
unsafety,
abi,
fn_token,
paren_token,
inputs,
variadic,
output,
}
}
process_struct! {
syn::TypeGroup {
group_token,
elem,
}
}
process_struct! {
syn::TypeImplTrait {
impl_token,
bounds,
}
}
process_struct! {
syn::TypeInfer {
underscore_token,
}
}
process_struct! {
syn::TypeMacro {
mac,
}
}
process_struct! {
syn::TypeNever {
bang_token,
}
}
process_struct! {
syn::TypeParam {
attrs,
ident,
colon_token,
bounds,
eq_token,
default,
}
}
process_struct! {
syn::TypeParen {
paren_token,
elem,
}
}
process_struct! {
syn::TypePath {
#[qself]
qself,
path,
}
}
process_struct! {
syn::TypePtr {
star_token,
const_token,
mutability,
elem,
}
}
process_struct! {
syn::TypeReference {
and_token,
lifetime,
mutability,
elem,
}
}
process_struct! {
syn::TypeSlice {
bracket_token,
elem,
}
}
process_struct! {
syn::TypeTraitObject {
dyn_token,
bounds,
}
}
process_struct! {
syn::TypeTuple {
paren_token,
elems,
}
}
process_struct! {
syn::UseGlob {
star_token,
}
}
process_struct! {
syn::UseGroup {
brace_token,
items,
}
}
process_struct! {
syn::UseName {
ident,
}
}
process_struct! {
syn::UsePath {
ident,
colon2_token,
tree,
}
}
process_struct! {
syn::UseRename {
ident,
as_token,
rename,
}
}
process_struct! {
syn::Variadic {
attrs,
pat,
dots,
comma,
}
}
process_struct! {
syn::Variant {
attrs,
ident,
fields,
discriminant,
}
}
process_struct! {
syn::VisRestricted {
pub_token,
paren_token,
in_token,
path,
}
}
process_struct! {
syn::WhereClause {
where_token,
predicates,
}
}
macro_rules! process_enum {
($path:path {
$($variant:ident$(($($field:ident),* $(,)?))?,)*
}) => {
impl<P: Phase> Process<P> for $path {
fn process(self, state: &mut State<P>) -> Option<Output<Self, P>> {
match self {
$(Self::$variant$(($($field),*))? => Some(($($($field.process(state)?,)*)?).call(|($($($field,)*)?)| Self::$variant$(($($field),*))?)),)*
}
}
}
};
($path:path {
$($variant:ident$(($($field:ident),* $(,)?))?,)*
#[no_op]
_,
}) => {
impl<P: Phase> Process<P> for $path {
fn process(self, state: &mut State<P>) -> Option<Output<Self, P>> {
#![allow(unused_variables)]
match self {
$(Self::$variant$(($($field),*))? => Some(($($($field.process(state)?,)*)?).call(|($($($field,)*)?)| Self::$variant$(($($field),*))?)),)*
_ => Some(Output::new(self)),
}
}
}
};
}
process_enum! {
syn::AttrStyle {
Outer,
Inner(f0),
}
}
process_enum! {
syn::BinOp {
Add(f0),
Sub(f0),
Mul(f0),
Div(f0),
Rem(f0),
And(f0),
Or(f0),
BitXor(f0),
BitAnd(f0),
BitOr(f0),
Shl(f0),
Shr(f0),
Eq(f0),
Lt(f0),
Le(f0),
Ne(f0),
Ge(f0),
Gt(f0),
AddAssign(f0),
SubAssign(f0),
MulAssign(f0),
DivAssign(f0),
RemAssign(f0),
BitXorAssign(f0),
BitAndAssign(f0),
BitOrAssign(f0),
ShlAssign(f0),
ShrAssign(f0),
#[no_op]
_,
}
}
process_enum! {
syn::CapturedParam {
Lifetime(f0),
Ident(f0),
#[no_op]
_,
}
}
process_enum! {
syn::Data {
Struct(f0),
Enum(f0),
Union(f0),
}
}
process_enum! {
syn::Expr {
Array(f0),
Assign(f0),
Async(f0),
Await(f0),
Binary(f0),
Block(f0),
Break(f0),
Call(f0),
Cast(f0),
Closure(f0),
Const(f0),
Continue(f0),
Field(f0),
ForLoop(f0),
Group(f0),
If(f0),
Index(f0),
Infer(f0),
Let(f0),
Lit(f0),
Loop(f0),
Macro(f0),
Match(f0),
MethodCall(f0),
Paren(f0),
Path(f0),
Range(f0),
RawAddr(f0),
Reference(f0),
Repeat(f0),
Return(f0),
Struct(f0),
Try(f0),
TryBlock(f0),
Tuple(f0),
Unary(f0),
Unsafe(f0),
Verbatim(f0),
While(f0),
Yield(f0),
#[no_op]
_,
}
}
process_enum! {
syn::FieldMutability {
None,
#[no_op]
_,
}
}
process_enum! {
syn::Fields {
Named(f0),
Unnamed(f0),
Unit,
}
}
process_enum! {
syn::FnArg {
Receiver(f0),
Typed(f0),
}
}
process_enum! {
syn::ForeignItem {
Fn(f0),
Static(f0),
Type(f0),
Macro(f0),
Verbatim(f0),
#[no_op]
_,
}
}
process_enum! {
syn::GenericArgument {
Lifetime(f0),
Type(f0),
Const(f0),
AssocType(f0),
AssocConst(f0),
Constraint(f0),
#[no_op]
_,
}
}
process_enum! {
syn::GenericParam {
Lifetime(f0),
Type(f0),
Const(f0),
}
}
process_enum! {
syn::ImplItem {
Const(f0),
Fn(f0),
Type(f0),
Macro(f0),
Verbatim(f0),
#[no_op]
_,
}
}
process_enum! {
syn::ImplRestriction {
#[no_op]
_,
}
}
process_enum! {
syn::Lit {
Str(f0),
ByteStr(f0),
CStr(f0),
Byte(f0),
Char(f0),
Int(f0),
Float(f0),
Bool(f0),
Verbatim(f0),
#[no_op]
_,
}
}
process_enum! {
syn::MacroDelimiter {
Paren(f0),
Brace(f0),
Bracket(f0),
}
}
process_enum! {
syn::Member {
Named(f0),
Unnamed(f0),
}
}
process_enum! {
syn::Meta {
Path(f0),
List(f0),
NameValue(f0),
}
}
process_enum! {
syn::Pat {
Const(f0),
Ident(f0),
Lit(f0),
Macro(f0),
Or(f0),
Paren(f0),
Path(f0),
Range(f0),
Reference(f0),
Rest(f0),
Slice(f0),
Struct(f0),
Tuple(f0),
TupleStruct(f0),
Type(f0),
Verbatim(f0),
Wild(f0),
#[no_op]
_,
}
}
process_enum! {
syn::PathArguments {
None,
AngleBracketed(f0),
Parenthesized(f0),
}
}
process_enum! {
syn::PointerMutability {
Const(f0),
Mut(f0),
}
}
process_enum! {
syn::RangeLimits {
HalfOpen(f0),
Closed(f0),
}
}
process_enum! {
syn::ReturnType {
Default,
Type(f0, f1),
}
}
process_enum! {
syn::StaticMutability {
Mut(f0),
None,
#[no_op]
_,
}
}
process_enum! {
syn::Stmt {
Local(f0),
Item(f0),
Expr(f0, f1),
Macro(f0),
}
}
process_enum! {
syn::TraitBoundModifier {
None,
Maybe(f0),
}
}
process_enum! {
syn::TraitItem {
Const(f0),
Fn(f0),
Type(f0),
Macro(f0),
Verbatim(f0),
#[no_op]
_,
}
}
process_enum! {
syn::Type {
Array(f0),
BareFn(f0),
Group(f0),
ImplTrait(f0),
Infer(f0),
Macro(f0),
Never(f0),
Paren(f0),
Path(f0),
Ptr(f0),
Reference(f0),
Slice(f0),
TraitObject(f0),
Tuple(f0),
Verbatim(f0),
#[no_op]
_,
}
}
process_enum! {
syn::TypeParamBound {
Trait(f0),
Lifetime(f0),
PreciseCapture(f0),
Verbatim(f0),
#[no_op]
_,
}
}
process_enum! {
syn::UnOp {
Deref(f0),
Not(f0),
Neg(f0),
#[no_op]
_,
}
}
process_enum! {
syn::UseTree {
Path(f0),
Name(f0),
Rename(f0),
Glob(f0),
Group(f0),
}
}
process_enum! {
syn::Visibility {
Public(f0),
Restricted(f0),
Inherited,
}
}
process_enum! {
syn::WherePredicate {
Lifetime(f0),
Type(f0),
#[no_op]
_,
}
}
struct TopItem(syn::Item);
impl<P: Phase> Process<P> for TopItem {
fn process(self, state: &mut State<P>) -> Option<Output<Self, P>> {
match self.0 {
syn::Item::Const(item) => Some(item.process(state)?.map(Into::into).map(TopItem)),
syn::Item::Enum(item) => Some(item.process(state)?.map(Into::into).map(TopItem)),
syn::Item::ExternCrate(item) => Some(item.process(state)?.map(Into::into).map(TopItem)),
syn::Item::Fn(item) => Some(item.process(state)?.map(Into::into).map(TopItem)),
syn::Item::ForeignMod(item) => Some(item.process(state)?.map(Into::into).map(TopItem)),
syn::Item::Impl(item) => Some(item.process(state)?.map(Into::into).map(TopItem)),
syn::Item::Macro(item) => Some(item.process(state)?.map(Into::into).map(TopItem)),
syn::Item::Mod(item) => Some(item.process(state)?.map(Into::into).map(TopItem)),
syn::Item::Static(item) => Some(item.process(state)?.map(Into::into).map(TopItem)),
syn::Item::Struct(item) => Some(item.process(state)?.map(Into::into).map(TopItem)),
syn::Item::Trait(item) => Some(item.process(state)?.map(Into::into).map(TopItem)),
syn::Item::TraitAlias(item) => Some(item.process(state)?.map(Into::into).map(TopItem)),
syn::Item::Type(item) => Some(item.process(state)?.map(Into::into).map(TopItem)),
syn::Item::Union(item) => Some(item.process(state)?.map(Into::into).map(TopItem)),
syn::Item::Use(item) => Some(item.process(state)?.map(Into::into).map(TopItem)),
_ => Some(Output::new(self)),
}
}
}
pub(crate) fn process_cfgs(item: syn::Item, cfgs: Cfgs<bool>) -> syn::Result<Option<syn::Item>> {
let mut state = State::<ProcessCfgsPhase> {
cfgs,
errors: Errors::new(),
_phantom: PhantomData,
};
let retval = TopItem(item).process(&mut state).map(|v| v.0 .0);
state.errors.finish()?;
Ok(retval)
}
pub(crate) fn collect_cfgs(item: syn::Item) -> syn::Result<Cfgs<()>> {
let mut state = State::<CollectCfgsPhase> {
cfgs: Cfgs::default(),
errors: Errors::new(),
_phantom: PhantomData,
};
let (None | Some(Output(()))) = TopItem(item).process(&mut state);
state.errors.finish()?;
Ok(state.cfgs)
}