at master 9.3 kB view raw
1// SPDX-License-Identifier: Apache-2.0 OR MIT 2 3use self::{Action::*, Input::*}; 4use proc_macro2::{Delimiter, Ident, Spacing, TokenTree}; 5use syn::parse::{ParseStream, Result}; 6use syn::{AngleBracketedGenericArguments, BinOp, Expr, ExprPath, Lifetime, Lit, Token, Type}; 7 8enum Input { 9 Keyword(&'static str), 10 Punct(&'static str), 11 ConsumeAny, 12 ConsumeBinOp, 13 ConsumeBrace, 14 ConsumeDelimiter, 15 ConsumeIdent, 16 ConsumeLifetime, 17 ConsumeLiteral, 18 ConsumeNestedBrace, 19 ExpectPath, 20 ExpectTurbofish, 21 ExpectType, 22 CanBeginExpr, 23 Otherwise, 24 Empty, 25} 26 27enum Action { 28 SetState(&'static [(Input, Action)]), 29 IncDepth, 30 DecDepth, 31 Finish, 32} 33 34static INIT: [(Input, Action); 28] = [ 35 (ConsumeDelimiter, SetState(&POSTFIX)), 36 (Keyword("async"), SetState(&ASYNC)), 37 (Keyword("break"), SetState(&BREAK_LABEL)), 38 (Keyword("const"), SetState(&CONST)), 39 (Keyword("continue"), SetState(&CONTINUE)), 40 (Keyword("for"), SetState(&FOR)), 41 (Keyword("if"), IncDepth), 42 (Keyword("let"), SetState(&PATTERN)), 43 (Keyword("loop"), SetState(&BLOCK)), 44 (Keyword("match"), IncDepth), 45 (Keyword("move"), SetState(&CLOSURE)), 46 (Keyword("return"), SetState(&RETURN)), 47 (Keyword("static"), SetState(&CLOSURE)), 48 (Keyword("unsafe"), SetState(&BLOCK)), 49 (Keyword("while"), IncDepth), 50 (Keyword("yield"), SetState(&RETURN)), 51 (Keyword("_"), SetState(&POSTFIX)), 52 (Punct("!"), SetState(&INIT)), 53 (Punct("#"), SetState(&[(ConsumeDelimiter, SetState(&INIT))])), 54 (Punct("&"), SetState(&REFERENCE)), 55 (Punct("*"), SetState(&INIT)), 56 (Punct("-"), SetState(&INIT)), 57 (Punct("..="), SetState(&INIT)), 58 (Punct(".."), SetState(&RANGE)), 59 (Punct("|"), SetState(&CLOSURE_ARGS)), 60 (ConsumeLifetime, SetState(&[(Punct(":"), SetState(&INIT))])), 61 (ConsumeLiteral, SetState(&POSTFIX)), 62 (ExpectPath, SetState(&PATH)), 63]; 64 65static POSTFIX: [(Input, Action); 10] = [ 66 (Keyword("as"), SetState(&[(ExpectType, SetState(&POSTFIX))])), 67 (Punct("..="), SetState(&INIT)), 68 (Punct(".."), SetState(&RANGE)), 69 (Punct("."), SetState(&DOT)), 70 (Punct("?"), SetState(&POSTFIX)), 71 (ConsumeBinOp, SetState(&INIT)), 72 (Punct("="), SetState(&INIT)), 73 (ConsumeNestedBrace, SetState(&IF_THEN)), 74 (ConsumeDelimiter, SetState(&POSTFIX)), 75 (Empty, Finish), 76]; 77 78static ASYNC: [(Input, Action); 3] = [ 79 (Keyword("move"), SetState(&ASYNC)), 80 (Punct("|"), SetState(&CLOSURE_ARGS)), 81 (ConsumeBrace, SetState(&POSTFIX)), 82]; 83 84static BLOCK: [(Input, Action); 1] = [(ConsumeBrace, SetState(&POSTFIX))]; 85 86static BREAK_LABEL: [(Input, Action); 2] = [ 87 (ConsumeLifetime, SetState(&BREAK_VALUE)), 88 (Otherwise, SetState(&BREAK_VALUE)), 89]; 90 91static BREAK_VALUE: [(Input, Action); 3] = [ 92 (ConsumeNestedBrace, SetState(&IF_THEN)), 93 (CanBeginExpr, SetState(&INIT)), 94 (Otherwise, SetState(&POSTFIX)), 95]; 96 97static CLOSURE: [(Input, Action); 7] = [ 98 (Keyword("async"), SetState(&CLOSURE)), 99 (Keyword("move"), SetState(&CLOSURE)), 100 (Punct(","), SetState(&CLOSURE)), 101 (Punct(">"), SetState(&CLOSURE)), 102 (Punct("|"), SetState(&CLOSURE_ARGS)), 103 (ConsumeLifetime, SetState(&CLOSURE)), 104 (ConsumeIdent, SetState(&CLOSURE)), 105]; 106 107static CLOSURE_ARGS: [(Input, Action); 2] = [ 108 (Punct("|"), SetState(&CLOSURE_RET)), 109 (ConsumeAny, SetState(&CLOSURE_ARGS)), 110]; 111 112static CLOSURE_RET: [(Input, Action); 2] = [ 113 (Punct("->"), SetState(&[(ExpectType, SetState(&BLOCK))])), 114 (Otherwise, SetState(&INIT)), 115]; 116 117static CONST: [(Input, Action); 2] = [ 118 (Punct("|"), SetState(&CLOSURE_ARGS)), 119 (ConsumeBrace, SetState(&POSTFIX)), 120]; 121 122static CONTINUE: [(Input, Action); 2] = [ 123 (ConsumeLifetime, SetState(&POSTFIX)), 124 (Otherwise, SetState(&POSTFIX)), 125]; 126 127static DOT: [(Input, Action); 3] = [ 128 (Keyword("await"), SetState(&POSTFIX)), 129 (ConsumeIdent, SetState(&METHOD)), 130 (ConsumeLiteral, SetState(&POSTFIX)), 131]; 132 133static FOR: [(Input, Action); 2] = [ 134 (Punct("<"), SetState(&CLOSURE)), 135 (Otherwise, SetState(&PATTERN)), 136]; 137 138static IF_ELSE: [(Input, Action); 2] = [(Keyword("if"), SetState(&INIT)), (ConsumeBrace, DecDepth)]; 139static IF_THEN: [(Input, Action); 2] = 140 [(Keyword("else"), SetState(&IF_ELSE)), (Otherwise, DecDepth)]; 141 142static METHOD: [(Input, Action); 1] = [(ExpectTurbofish, SetState(&POSTFIX))]; 143 144static PATH: [(Input, Action); 4] = [ 145 (Punct("!="), SetState(&INIT)), 146 (Punct("!"), SetState(&INIT)), 147 (ConsumeNestedBrace, SetState(&IF_THEN)), 148 (Otherwise, SetState(&POSTFIX)), 149]; 150 151static PATTERN: [(Input, Action); 15] = [ 152 (ConsumeDelimiter, SetState(&PATTERN)), 153 (Keyword("box"), SetState(&PATTERN)), 154 (Keyword("in"), IncDepth), 155 (Keyword("mut"), SetState(&PATTERN)), 156 (Keyword("ref"), SetState(&PATTERN)), 157 (Keyword("_"), SetState(&PATTERN)), 158 (Punct("!"), SetState(&PATTERN)), 159 (Punct("&"), SetState(&PATTERN)), 160 (Punct("..="), SetState(&PATTERN)), 161 (Punct(".."), SetState(&PATTERN)), 162 (Punct("="), SetState(&INIT)), 163 (Punct("@"), SetState(&PATTERN)), 164 (Punct("|"), SetState(&PATTERN)), 165 (ConsumeLiteral, SetState(&PATTERN)), 166 (ExpectPath, SetState(&PATTERN)), 167]; 168 169static RANGE: [(Input, Action); 6] = [ 170 (Punct("..="), SetState(&INIT)), 171 (Punct(".."), SetState(&RANGE)), 172 (Punct("."), SetState(&DOT)), 173 (ConsumeNestedBrace, SetState(&IF_THEN)), 174 (Empty, Finish), 175 (Otherwise, SetState(&INIT)), 176]; 177 178static RAW: [(Input, Action); 3] = [ 179 (Keyword("const"), SetState(&INIT)), 180 (Keyword("mut"), SetState(&INIT)), 181 (Otherwise, SetState(&POSTFIX)), 182]; 183 184static REFERENCE: [(Input, Action); 3] = [ 185 (Keyword("mut"), SetState(&INIT)), 186 (Keyword("raw"), SetState(&RAW)), 187 (Otherwise, SetState(&INIT)), 188]; 189 190static RETURN: [(Input, Action); 2] = [ 191 (CanBeginExpr, SetState(&INIT)), 192 (Otherwise, SetState(&POSTFIX)), 193]; 194 195pub(crate) fn scan_expr(input: ParseStream) -> Result<()> { 196 let mut state = INIT.as_slice(); 197 let mut depth = 0usize; 198 'table: loop { 199 for rule in state { 200 if match rule.0 { 201 Input::Keyword(expected) => input.step(|cursor| match cursor.ident() { 202 Some((ident, rest)) if ident == expected => Ok((true, rest)), 203 _ => Ok((false, *cursor)), 204 })?, 205 Input::Punct(expected) => input.step(|cursor| { 206 let begin = *cursor; 207 let mut cursor = begin; 208 for (i, ch) in expected.chars().enumerate() { 209 match cursor.punct() { 210 Some((punct, _)) if punct.as_char() != ch => break, 211 Some((_, rest)) if i == expected.len() - 1 => { 212 return Ok((true, rest)); 213 } 214 Some((punct, rest)) if punct.spacing() == Spacing::Joint => { 215 cursor = rest; 216 } 217 _ => break, 218 } 219 } 220 Ok((false, begin)) 221 })?, 222 Input::ConsumeAny => input.parse::<Option<TokenTree>>()?.is_some(), 223 Input::ConsumeBinOp => input.parse::<BinOp>().is_ok(), 224 Input::ConsumeBrace | Input::ConsumeNestedBrace => { 225 (matches!(rule.0, Input::ConsumeBrace) || depth > 0) 226 && input.step(|cursor| match cursor.group(Delimiter::Brace) { 227 Some((_inside, _span, rest)) => Ok((true, rest)), 228 None => Ok((false, *cursor)), 229 })? 230 } 231 Input::ConsumeDelimiter => input.step(|cursor| match cursor.any_group() { 232 Some((_inside, _delimiter, _span, rest)) => Ok((true, rest)), 233 None => Ok((false, *cursor)), 234 })?, 235 Input::ConsumeIdent => input.parse::<Option<Ident>>()?.is_some(), 236 Input::ConsumeLifetime => input.parse::<Option<Lifetime>>()?.is_some(), 237 Input::ConsumeLiteral => input.parse::<Option<Lit>>()?.is_some(), 238 Input::ExpectPath => { 239 input.parse::<ExprPath>()?; 240 true 241 } 242 Input::ExpectTurbofish => { 243 if input.peek(Token![::]) { 244 input.parse::<AngleBracketedGenericArguments>()?; 245 } 246 true 247 } 248 Input::ExpectType => { 249 Type::without_plus(input)?; 250 true 251 } 252 Input::CanBeginExpr => Expr::peek(input), 253 Input::Otherwise => true, 254 Input::Empty => input.is_empty() || input.peek(Token![,]), 255 } { 256 state = match rule.1 { 257 Action::SetState(next) => next, 258 Action::IncDepth => (depth += 1, &INIT).1, 259 Action::DecDepth => (depth -= 1, &POSTFIX).1, 260 Action::Finish => return if depth == 0 { Ok(()) } else { break }, 261 }; 262 continue 'table; 263 } 264 } 265 return Err(input.error("unsupported expression")); 266 } 267}