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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//!
//! Utils for `join!` macro parsing and code generation.
//!

use proc_macro2::{TokenStream, TokenTree};
use quote::ToTokens;
use std::fmt::Debug;
use syn::parse::{Parse, ParseStream};
use syn::{parse2, Expr};

use super::unit::{Unit, UnitResult};
use crate::chain::group::{ActionGroup, ApplicationType, Combinator, GroupDeterminer, MoveType};

///
/// Returns `true` if given stream is valid `Expr`.
///
pub fn is_valid_expr(input: TokenStream) -> bool {
    is_valid_stream::<Expr>(input)
}

///
/// Returns `true` if given stream can be parsed as `T`.
///
pub fn is_valid_stream<T: Parse>(input: TokenStream) -> bool {
    syn::parse2::<T>(input).is_ok()
}

///
/// Returns `true` if expr is {...}.
///
pub fn is_block_expr(expr: &Expr) -> bool {
    matches!(expr, Expr::Block(_))
}

///
/// Parses input `ParseStream` until one of provided `GroupDeterminer`'s check will be valid or it reaches end.
///
pub fn parse_until<'a, T: Parse + Clone + Debug>(
    input: ParseStream<'_>,
    group_determiners: impl Iterator<Item = &'a GroupDeterminer> + Clone,
    deferred_determiner: &'a GroupDeterminer,
    wrapper_determiner: &'a GroupDeterminer,
    allow_empty_parsed: bool,
) -> UnitResult<T, ActionGroup> {
    let group_count = group_determiners.clone().count();
    let mut group_determiners = group_determiners.cycle();

    let mut tokens = TokenStream::new();
    let mut next = None;
    let mut deferred = false;
    let mut wrap = false;

    while !input.is_empty()
        && !{
            let group_determiners = &mut group_determiners;

            deferred = deferred_determiner.check_input(input);
            if deferred {
                deferred_determiner.erase_input(input)?;
            }

            let possible_group = group_determiners
                .take(group_count)
                .find(|group| group.check_input(input));
            possible_group
                .map(|group| {
                    tokens.is_empty() && allow_empty_parsed
                        || group.check_parsed::<T>(tokens.clone())
                })
                .unwrap_or(false)
                && {
                    next = possible_group;
                    true
                }
        }
    {
        let next: TokenTree = input.parse()?;
        next.to_tokens(&mut tokens);
    }

    //
    // Parses group determiner's tokens. (for ex. => -> |> etc.)
    //
    if let Some(group) = next {
        if let Some(combinator) = group.combinator() {
            let forked = input.fork();
            group.erase_input(&forked)?;

            wrap = wrapper_determiner.check_input(&forked);
            if wrap && combinator == Combinator::UNWRAP {
                return Err(input.error("Action can be either wrapped or unwrapped but not both"));
            } else if wrap && !combinator.can_be_wrapper() {
                return Err(input.error("This combinator can't be wrapper"));
            }
            if wrap {
                wrapper_determiner.erase_input(input)?;
            }
        }
        group.erase_input(input)?;
    }

    Ok(Unit {
        parsed: parse2(tokens)?,
        next: next.and_then(|group| {
            group.combinator().map(|combinator| {
                ActionGroup::new(
                    combinator,
                    if deferred {
                        ApplicationType::Deferred
                    } else {
                        ApplicationType::Instant
                    },
                    if wrap {
                        MoveType::Wrap
                    } else if combinator == Combinator::UNWRAP {
                        MoveType::Unwrap
                    } else {
                        MoveType::None
                    },
                )
            })
        }),
    })
}

///
/// Skips next item in `ParseStream`. Returns `true` in case of success.
///
pub fn skip(input: ParseStream<'_>) -> bool {
    input
        .step(|cursor| {
            if let Some((_lifetime, rest)) = cursor.lifetime() {
                Ok((true, rest))
            } else if let Some((_token, rest)) = cursor.token_tree() {
                Ok((true, rest))
            } else {
                Ok((false, *cursor))
            }
        })
        .unwrap()
}