macro_rules! state_body {
    ( | [ $self:tt, $input:ident, $ch:ident ] |> [$($arms:tt)+], [$($enter_actions:tt)*] ) => {
        action_list!(@state_enter |$self, $input|> $($enter_actions)*);
        state_body!(@map_arms | [$self, $input, $ch] |> [$($arms)+], [])
    };
    ( @map_arms
        | $scope_vars:tt |>
        [ $pat:tt => ( $($actions:tt)* ) $($rest:tt)* ], [ $($expanded:tt)* ]
    ) => {
        arm_pattern!(|[ $scope_vars, [$($rest)*], [$($expanded)*] ]|> $pat => ( $($actions)* ))
    };
    ( @map_arms
        | $scope_vars:tt |>
        [], [$($expanded:tt)*]
    ) => {
        state_body!(@match_block |$scope_vars|> $($expanded)*);
    };
    ( @callback
        | [ $scope_vars:tt, [$($pending:tt)*], [$($expanded:tt)*] ] |>
        $($expanded_arm:tt)*
    ) => {
        state_body!(@map_arms | $scope_vars |> [$($pending)*], [$($expanded)* $($expanded_arm)*])
    };
    ( @match_block
        | [ $self:tt, $input:ident, $ch:ident ] |>
        $( $pat:pat_param $(|$pat_cont:pat)* $(if $pat_expr:expr)* => ( $($actions:tt)* ) )*
    ) => {
        #[deny(unreachable_patterns)]
        match $ch {
            $(
                $pat $(| $pat_cont)* $(if $pat_expr)* => {
                    action_list!(|$self, $input|> $($actions)*);
                }
            )*
        }
    };
}