267 lines · 9.1 KB · Rust
RawDownload
// SPDX-License-Identifier: Apache-2.0 OR MIT use self::{Action::*, Input::*};use proc_macro2::{Delimiter, Ident, Spacing, TokenTree};use syn::parse::{ParseStream, Result};use syn::{AngleBracketedGenericArguments, BinOp, Expr, ExprPath, Lifetime, Lit, Token, Type}; enum Input {    Keyword(&'static str),    Punct(&'static str),    ConsumeAny,    ConsumeBinOp,    ConsumeBrace,    ConsumeDelimiter,    ConsumeIdent,    ConsumeLifetime,    ConsumeLiteral,    ConsumeNestedBrace,    ExpectPath,    ExpectTurbofish,    ExpectType,    CanBeginExpr,    Otherwise,    Empty,} enum Action {    SetState(&'static [(Input, Action)]),    IncDepth,    DecDepth,    Finish,} static INIT: [(Input, Action); 28] = [    (ConsumeDelimiter, SetState(&POSTFIX)),    (Keyword("async"), SetState(&ASYNC)),    (Keyword("break"), SetState(&BREAK_LABEL)),    (Keyword("const"), SetState(&CONST)),    (Keyword("continue"), SetState(&CONTINUE)),    (Keyword("for"), SetState(&FOR)),    (Keyword("if"), IncDepth),    (Keyword("let"), SetState(&PATTERN)),    (Keyword("loop"), SetState(&BLOCK)),    (Keyword("match"), IncDepth),    (Keyword("move"), SetState(&CLOSURE)),    (Keyword("return"), SetState(&RETURN)),    (Keyword("static"), SetState(&CLOSURE)),    (Keyword("unsafe"), SetState(&BLOCK)),    (Keyword("while"), IncDepth),    (Keyword("yield"), SetState(&RETURN)),    (Keyword("_"), SetState(&POSTFIX)),    (Punct("!"), SetState(&INIT)),    (Punct("#"), SetState(&[(ConsumeDelimiter, SetState(&INIT))])),    (Punct("&"), SetState(&REFERENCE)),    (Punct("*"), SetState(&INIT)),    (Punct("-"), SetState(&INIT)),    (Punct("..="), SetState(&INIT)),    (Punct(".."), SetState(&RANGE)),    (Punct("|"), SetState(&CLOSURE_ARGS)),    (ConsumeLifetime, SetState(&[(Punct(":"), SetState(&INIT))])),    (ConsumeLiteral, SetState(&POSTFIX)),    (ExpectPath, SetState(&PATH)),]; static POSTFIX: [(Input, Action); 10] = [    (Keyword("as"), SetState(&[(ExpectType, SetState(&POSTFIX))])),    (Punct("..="), SetState(&INIT)),    (Punct(".."), SetState(&RANGE)),    (Punct("."), SetState(&DOT)),    (Punct("?"), SetState(&POSTFIX)),    (ConsumeBinOp, SetState(&INIT)),    (Punct("="), SetState(&INIT)),    (ConsumeNestedBrace, SetState(&IF_THEN)),    (ConsumeDelimiter, SetState(&POSTFIX)),    (Empty, Finish),]; static ASYNC: [(Input, Action); 3] = [    (Keyword("move"), SetState(&ASYNC)),    (Punct("|"), SetState(&CLOSURE_ARGS)),    (ConsumeBrace, SetState(&POSTFIX)),]; static BLOCK: [(Input, Action); 1] = [(ConsumeBrace, SetState(&POSTFIX))]; static BREAK_LABEL: [(Input, Action); 2] = [    (ConsumeLifetime, SetState(&BREAK_VALUE)),    (Otherwise, SetState(&BREAK_VALUE)),]; static BREAK_VALUE: [(Input, Action); 3] = [    (ConsumeNestedBrace, SetState(&IF_THEN)),    (CanBeginExpr, SetState(&INIT)),    (Otherwise, SetState(&POSTFIX)),]; static CLOSURE: [(Input, Action); 7] = [    (Keyword("async"), SetState(&CLOSURE)),    (Keyword("move"), SetState(&CLOSURE)),    (Punct(","), SetState(&CLOSURE)),    (Punct(">"), SetState(&CLOSURE)),    (Punct("|"), SetState(&CLOSURE_ARGS)),    (ConsumeLifetime, SetState(&CLOSURE)),    (ConsumeIdent, SetState(&CLOSURE)),]; static CLOSURE_ARGS: [(Input, Action); 2] = [    (Punct("|"), SetState(&CLOSURE_RET)),    (ConsumeAny, SetState(&CLOSURE_ARGS)),]; static CLOSURE_RET: [(Input, Action); 2] = [    (Punct("->"), SetState(&[(ExpectType, SetState(&BLOCK))])),    (Otherwise, SetState(&INIT)),]; static CONST: [(Input, Action); 2] = [    (Punct("|"), SetState(&CLOSURE_ARGS)),    (ConsumeBrace, SetState(&POSTFIX)),]; static CONTINUE: [(Input, Action); 2] = [    (ConsumeLifetime, SetState(&POSTFIX)),    (Otherwise, SetState(&POSTFIX)),]; static DOT: [(Input, Action); 3] = [    (Keyword("await"), SetState(&POSTFIX)),    (ConsumeIdent, SetState(&METHOD)),    (ConsumeLiteral, SetState(&POSTFIX)),]; static FOR: [(Input, Action); 2] = [    (Punct("<"), SetState(&CLOSURE)),    (Otherwise, SetState(&PATTERN)),]; static IF_ELSE: [(Input, Action); 2] = [(Keyword("if"), SetState(&INIT)), (ConsumeBrace, DecDepth)];static IF_THEN: [(Input, Action); 2] =    [(Keyword("else"), SetState(&IF_ELSE)), (Otherwise, DecDepth)]; static METHOD: [(Input, Action); 1] = [(ExpectTurbofish, SetState(&POSTFIX))]; static PATH: [(Input, Action); 4] = [    (Punct("!="), SetState(&INIT)),    (Punct("!"), SetState(&INIT)),    (ConsumeNestedBrace, SetState(&IF_THEN)),    (Otherwise, SetState(&POSTFIX)),]; static PATTERN: [(Input, Action); 15] = [    (ConsumeDelimiter, SetState(&PATTERN)),    (Keyword("box"), SetState(&PATTERN)),    (Keyword("in"), IncDepth),    (Keyword("mut"), SetState(&PATTERN)),    (Keyword("ref"), SetState(&PATTERN)),    (Keyword("_"), SetState(&PATTERN)),    (Punct("!"), SetState(&PATTERN)),    (Punct("&"), SetState(&PATTERN)),    (Punct("..="), SetState(&PATTERN)),    (Punct(".."), SetState(&PATTERN)),    (Punct("="), SetState(&INIT)),    (Punct("@"), SetState(&PATTERN)),    (Punct("|"), SetState(&PATTERN)),    (ConsumeLiteral, SetState(&PATTERN)),    (ExpectPath, SetState(&PATTERN)),]; static RANGE: [(Input, Action); 6] = [    (Punct("..="), SetState(&INIT)),    (Punct(".."), SetState(&RANGE)),    (Punct("."), SetState(&DOT)),    (ConsumeNestedBrace, SetState(&IF_THEN)),    (Empty, Finish),    (Otherwise, SetState(&INIT)),]; static RAW: [(Input, Action); 3] = [    (Keyword("const"), SetState(&INIT)),    (Keyword("mut"), SetState(&INIT)),    (Otherwise, SetState(&POSTFIX)),]; static REFERENCE: [(Input, Action); 3] = [    (Keyword("mut"), SetState(&INIT)),    (Keyword("raw"), SetState(&RAW)),    (Otherwise, SetState(&INIT)),]; static RETURN: [(Input, Action); 2] = [    (CanBeginExpr, SetState(&INIT)),    (Otherwise, SetState(&POSTFIX)),]; pub(crate) fn scan_expr(input: ParseStream) -> Result<()> {    let mut state = INIT.as_slice();    let mut depth = 0usize;    'table: loop {        for rule in state {            if match rule.0 {                Input::Keyword(expected) => input.step(|cursor| match cursor.ident() {                    Some((ident, rest)) if ident == expected => Ok((true, rest)),                    _ => Ok((false, *cursor)),                })?,                Input::Punct(expected) => input.step(|cursor| {                    let begin = *cursor;                    let mut cursor = begin;                    for (i, ch) in expected.chars().enumerate() {                        match cursor.punct() {                            Some((punct, _)) if punct.as_char() != ch => break,                            Some((_, rest)) if i == expected.len() - 1 => {                                return Ok((true, rest));                            }                            Some((punct, rest)) if punct.spacing() == Spacing::Joint => {                                cursor = rest;                            }                            _ => break,                        }                    }                    Ok((false, begin))                })?,                Input::ConsumeAny => input.parse::<Option<TokenTree>>()?.is_some(),                Input::ConsumeBinOp => input.parse::<BinOp>().is_ok(),                Input::ConsumeBrace | Input::ConsumeNestedBrace => {                    (matches!(rule.0, Input::ConsumeBrace) || depth > 0)                        && input.step(|cursor| match cursor.group(Delimiter::Brace) {                            Some((_inside, _span, rest)) => Ok((true, rest)),                            None => Ok((false, *cursor)),                        })?                }                Input::ConsumeDelimiter => input.step(|cursor| match cursor.any_group() {                    Some((_inside, _delimiter, _span, rest)) => Ok((true, rest)),                    None => Ok((false, *cursor)),                })?,                Input::ConsumeIdent => input.parse::<Option<Ident>>()?.is_some(),                Input::ConsumeLifetime => input.parse::<Option<Lifetime>>()?.is_some(),                Input::ConsumeLiteral => input.parse::<Option<Lit>>()?.is_some(),                Input::ExpectPath => {                    input.parse::<ExprPath>()?;                    true                }                Input::ExpectTurbofish => {                    if input.peek(Token![::]) {                        input.parse::<AngleBracketedGenericArguments>()?;                    }                    true                }                Input::ExpectType => {                    Type::without_plus(input)?;                    true                }                Input::CanBeginExpr => Expr::peek(input),                Input::Otherwise => true,                Input::Empty => input.is_empty() || input.peek(Token![,]),            } {                state = match rule.1 {                    Action::SetState(next) => next,                    Action::IncDepth => (depth += 1, &INIT).1,                    Action::DecDepth => (depth -= 1, &POSTFIX).1,                    Action::Finish => return if depth == 0 { Ok(()) } else { break },                };                continue 'table;            }        }        return Err(input.error("unsupported expression"));    }}