| 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); 6] = [ | 
|---|
| 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 | ]; | 
|---|
| 103 |  | 
|---|
| 104 | static CLOSURE_ARGS: [(Input, Action); 2] = [ | 
|---|
| 105 | (Punct( "|"), SetState(&CLOSURE_RET)), | 
|---|
| 106 | (ConsumeAny, SetState(&CLOSURE_ARGS)), | 
|---|
| 107 | ]; | 
|---|
| 108 |  | 
|---|
| 109 | static CLOSURE_RET: [(Input, Action); 2] = [ | 
|---|
| 110 | (Punct( "->"), SetState(&[(ExpectType, SetState(&BLOCK))])), | 
|---|
| 111 | (Otherwise, SetState(&INIT)), | 
|---|
| 112 | ]; | 
|---|
| 113 |  | 
|---|
| 114 | static CONST: [(Input, Action); 2] = [ | 
|---|
| 115 | (Punct( "|"), SetState(&CLOSURE_ARGS)), | 
|---|
| 116 | (ConsumeBrace, SetState(&POSTFIX)), | 
|---|
| 117 | ]; | 
|---|
| 118 |  | 
|---|
| 119 | static CONTINUE: [(Input, Action); 2] = [ | 
|---|
| 120 | (ConsumeLifetime, SetState(&POSTFIX)), | 
|---|
| 121 | (Otherwise, SetState(&POSTFIX)), | 
|---|
| 122 | ]; | 
|---|
| 123 |  | 
|---|
| 124 | static DOT: [(Input, Action); 3] = [ | 
|---|
| 125 | (Keyword( "await"), SetState(&POSTFIX)), | 
|---|
| 126 | (ConsumeIdent, SetState(&METHOD)), | 
|---|
| 127 | (ConsumeLiteral, SetState(&POSTFIX)), | 
|---|
| 128 | ]; | 
|---|
| 129 |  | 
|---|
| 130 | static FOR: [(Input, Action); 2] = [ | 
|---|
| 131 | (Punct( "<"), SetState(&CLOSURE)), | 
|---|
| 132 | (Otherwise, SetState(&PATTERN)), | 
|---|
| 133 | ]; | 
|---|
| 134 |  | 
|---|
| 135 | static IF_ELSE: [(Input, Action); 2] = [(Keyword( "if"), SetState(&INIT)), (ConsumeBrace, DecDepth)]; | 
|---|
| 136 | static IF_THEN: [(Input, Action); 2] = | 
|---|
| 137 | [(Keyword( "else"), SetState(&IF_ELSE)), (Otherwise, DecDepth)]; | 
|---|
| 138 |  | 
|---|
| 139 | static METHOD: [(Input, Action); 1] = [(ExpectTurbofish, SetState(&POSTFIX))]; | 
|---|
| 140 |  | 
|---|
| 141 | static PATH: [(Input, Action); 4] = [ | 
|---|
| 142 | (Punct( "!="), SetState(&INIT)), | 
|---|
| 143 | (Punct( "!"), SetState(&INIT)), | 
|---|
| 144 | (ConsumeNestedBrace, SetState(&IF_THEN)), | 
|---|
| 145 | (Otherwise, SetState(&POSTFIX)), | 
|---|
| 146 | ]; | 
|---|
| 147 |  | 
|---|
| 148 | static PATTERN: [(Input, Action); 15] = [ | 
|---|
| 149 | (ConsumeDelimiter, SetState(&PATTERN)), | 
|---|
| 150 | (Keyword( "box"), SetState(&PATTERN)), | 
|---|
| 151 | (Keyword( "in"), IncDepth), | 
|---|
| 152 | (Keyword( "mut"), SetState(&PATTERN)), | 
|---|
| 153 | (Keyword( "ref"), SetState(&PATTERN)), | 
|---|
| 154 | (Keyword( "_"), SetState(&PATTERN)), | 
|---|
| 155 | (Punct( "!"), SetState(&PATTERN)), | 
|---|
| 156 | (Punct( "&"), SetState(&PATTERN)), | 
|---|
| 157 | (Punct( "..="), SetState(&PATTERN)), | 
|---|
| 158 | (Punct( ".."), SetState(&PATTERN)), | 
|---|
| 159 | (Punct( "="), SetState(&INIT)), | 
|---|
| 160 | (Punct( "@"), SetState(&PATTERN)), | 
|---|
| 161 | (Punct( "|"), SetState(&PATTERN)), | 
|---|
| 162 | (ConsumeLiteral, SetState(&PATTERN)), | 
|---|
| 163 | (ExpectPath, SetState(&PATTERN)), | 
|---|
| 164 | ]; | 
|---|
| 165 |  | 
|---|
| 166 | static RANGE: [(Input, Action); 6] = [ | 
|---|
| 167 | (Punct( "..="), SetState(&INIT)), | 
|---|
| 168 | (Punct( ".."), SetState(&RANGE)), | 
|---|
| 169 | (Punct( "."), SetState(&DOT)), | 
|---|
| 170 | (ConsumeNestedBrace, SetState(&IF_THEN)), | 
|---|
| 171 | (Empty, Finish), | 
|---|
| 172 | (Otherwise, SetState(&INIT)), | 
|---|
| 173 | ]; | 
|---|
| 174 |  | 
|---|
| 175 | static RAW: [(Input, Action); 3] = [ | 
|---|
| 176 | (Keyword( "const"), SetState(&INIT)), | 
|---|
| 177 | (Keyword( "mut"), SetState(&INIT)), | 
|---|
| 178 | (Otherwise, SetState(&POSTFIX)), | 
|---|
| 179 | ]; | 
|---|
| 180 |  | 
|---|
| 181 | static REFERENCE: [(Input, Action); 3] = [ | 
|---|
| 182 | (Keyword( "mut"), SetState(&INIT)), | 
|---|
| 183 | (Keyword( "raw"), SetState(&RAW)), | 
|---|
| 184 | (Otherwise, SetState(&INIT)), | 
|---|
| 185 | ]; | 
|---|
| 186 |  | 
|---|
| 187 | static RETURN: [(Input, Action); 2] = [ | 
|---|
| 188 | (CanBeginExpr, SetState(&INIT)), | 
|---|
| 189 | (Otherwise, SetState(&POSTFIX)), | 
|---|
| 190 | ]; | 
|---|
| 191 |  | 
|---|
| 192 | pub(crate) fn scan_expr(input: ParseStream) -> Result<()> { | 
|---|
| 193 | let mut state = INIT.as_slice(); | 
|---|
| 194 | let mut depth = 0usize; | 
|---|
| 195 | 'table: loop { | 
|---|
| 196 | for rule in state { | 
|---|
| 197 | if match rule.0 { | 
|---|
| 198 | Input::Keyword(expected) => input.step(|cursor| match cursor.ident() { | 
|---|
| 199 | Some((ident, rest)) if ident == expected => Ok((true, rest)), | 
|---|
| 200 | _ => Ok((false, *cursor)), | 
|---|
| 201 | })?, | 
|---|
| 202 | Input::Punct(expected) => input.step(|cursor| { | 
|---|
| 203 | let begin = *cursor; | 
|---|
| 204 | let mut cursor = begin; | 
|---|
| 205 | for (i, ch) in expected.chars().enumerate() { | 
|---|
| 206 | match cursor.punct() { | 
|---|
| 207 | Some((punct, _)) if punct.as_char() != ch => break, | 
|---|
| 208 | Some((_, rest)) if i == expected.len() - 1 => { | 
|---|
| 209 | return Ok((true, rest)); | 
|---|
| 210 | } | 
|---|
| 211 | Some((punct, rest)) if punct.spacing() == Spacing::Joint => { | 
|---|
| 212 | cursor = rest; | 
|---|
| 213 | } | 
|---|
| 214 | _ => break, | 
|---|
| 215 | } | 
|---|
| 216 | } | 
|---|
| 217 | Ok((false, begin)) | 
|---|
| 218 | })?, | 
|---|
| 219 | Input::ConsumeAny => input.parse::<Option<TokenTree>>()?.is_some(), | 
|---|
| 220 | Input::ConsumeBinOp => input.parse::<BinOp>().is_ok(), | 
|---|
| 221 | Input::ConsumeBrace | Input::ConsumeNestedBrace => { | 
|---|
| 222 | (matches!(rule.0, Input::ConsumeBrace) || depth > 0) | 
|---|
| 223 | && input.step(|cursor| match cursor.group(Delimiter::Brace) { | 
|---|
| 224 | Some((_inside, _span, rest)) => Ok((true, rest)), | 
|---|
| 225 | None => Ok((false, *cursor)), | 
|---|
| 226 | })? | 
|---|
| 227 | } | 
|---|
| 228 | Input::ConsumeDelimiter => input.step(|cursor| match cursor.any_group() { | 
|---|
| 229 | Some((_inside, _delimiter, _span, rest)) => Ok((true, rest)), | 
|---|
| 230 | None => Ok((false, *cursor)), | 
|---|
| 231 | })?, | 
|---|
| 232 | Input::ConsumeIdent => input.parse::<Option<Ident>>()?.is_some(), | 
|---|
| 233 | Input::ConsumeLifetime => input.parse::<Option<Lifetime>>()?.is_some(), | 
|---|
| 234 | Input::ConsumeLiteral => input.parse::<Option<Lit>>()?.is_some(), | 
|---|
| 235 | Input::ExpectPath => { | 
|---|
| 236 | input.parse::<ExprPath>()?; | 
|---|
| 237 | true | 
|---|
| 238 | } | 
|---|
| 239 | Input::ExpectTurbofish => { | 
|---|
| 240 | if input.peek(Token![::]) { | 
|---|
| 241 | input.parse::<AngleBracketedGenericArguments>()?; | 
|---|
| 242 | } | 
|---|
| 243 | true | 
|---|
| 244 | } | 
|---|
| 245 | Input::ExpectType => { | 
|---|
| 246 | Type::without_plus(input)?; | 
|---|
| 247 | true | 
|---|
| 248 | } | 
|---|
| 249 | Input::CanBeginExpr => Expr::peek(input), | 
|---|
| 250 | Input::Otherwise => true, | 
|---|
| 251 | Input::Empty => input.is_empty() || input.peek(Token![,]), | 
|---|
| 252 | } { | 
|---|
| 253 | state = match rule.1 { | 
|---|
| 254 | Action::SetState(next) => next, | 
|---|
| 255 | Action::IncDepth => (depth += 1, &INIT).1, | 
|---|
| 256 | Action::DecDepth => (depth -= 1, &POSTFIX).1, | 
|---|
| 257 | Action::Finish => return if depth == 0 { Ok(()) } else { break }, | 
|---|
| 258 | }; | 
|---|
| 259 | continue 'table; | 
|---|
| 260 | } | 
|---|
| 261 | } | 
|---|
| 262 | return Err(input.error( "unsupported expression")); | 
|---|
| 263 | } | 
|---|
| 264 | } | 
|---|
| 265 |  | 
|---|