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