| 1 | |
| 2 |
|
| 3 | use self::{Action::*, Input::*};
|
| 4 | use proc_macro2::{Delimiter, Ident, Spacing, TokenTree};
|
| 5 | use syn::parse::{ParseStream, Result};
|
| 6 | use syn::{AngleBracketedGenericArguments, BinOp, Expr, ExprPath, Lifetime, Lit, Token, Type};
|
| 7 |
|
| 8 | enum 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 |
|
| 27 | enum Action {
|
| 28 | SetState(&'static [(Input, Action)]),
|
| 29 | IncDepth,
|
| 30 | DecDepth,
|
| 31 | Finish,
|
| 32 | }
|
| 33 |
|
| 34 | static 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 |
|
| 65 | static 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 |
|
| 78 | static ASYNC: [(Input, Action); 3] = [
|
| 79 | (Keyword("move"), SetState(&ASYNC)),
|
| 80 | (Punct("|"), SetState(&CLOSURE_ARGS)),
|
| 81 | (ConsumeBrace, SetState(&POSTFIX)),
|
| 82 | ];
|
| 83 |
|
| 84 | static BLOCK: [(Input, Action); 1] = [(ConsumeBrace, SetState(&POSTFIX))];
|
| 85 |
|
| 86 | static BREAK_LABEL: [(Input, Action); 2] = [
|
| 87 | (ConsumeLifetime, SetState(&BREAK_VALUE)),
|
| 88 | (Otherwise, SetState(&BREAK_VALUE)),
|
| 89 | ];
|
| 90 |
|
| 91 | static BREAK_VALUE: [(Input, Action); 3] = [
|
| 92 | (ConsumeNestedBrace, SetState(&IF_THEN)),
|
| 93 | (CanBeginExpr, SetState(&INIT)),
|
| 94 | (Otherwise, SetState(&POSTFIX)),
|
| 95 | ];
|
| 96 |
|
| 97 | static 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 |
|
| 107 | static CLOSURE_ARGS: [(Input, Action); 2] = [
|
| 108 | (Punct("|"), SetState(&CLOSURE_RET)),
|
| 109 | (ConsumeAny, SetState(&CLOSURE_ARGS)),
|
| 110 | ];
|
| 111 |
|
| 112 | static CLOSURE_RET: [(Input, Action); 2] = [
|
| 113 | (Punct("->"), SetState(&[(ExpectType, SetState(&BLOCK))])),
|
| 114 | (Otherwise, SetState(&INIT)),
|
| 115 | ];
|
| 116 |
|
| 117 | static CONST: [(Input, Action); 2] = [
|
| 118 | (Punct("|"), SetState(&CLOSURE_ARGS)),
|
| 119 | (ConsumeBrace, SetState(&POSTFIX)),
|
| 120 | ];
|
| 121 |
|
| 122 | static CONTINUE: [(Input, Action); 2] = [
|
| 123 | (ConsumeLifetime, SetState(&POSTFIX)),
|
| 124 | (Otherwise, SetState(&POSTFIX)),
|
| 125 | ];
|
| 126 |
|
| 127 | static DOT: [(Input, Action); 3] = [
|
| 128 | (Keyword("await"), SetState(&POSTFIX)),
|
| 129 | (ConsumeIdent, SetState(&METHOD)),
|
| 130 | (ConsumeLiteral, SetState(&POSTFIX)),
|
| 131 | ];
|
| 132 |
|
| 133 | static FOR: [(Input, Action); 2] = [
|
| 134 | (Punct("<"), SetState(&CLOSURE)),
|
| 135 | (Otherwise, SetState(&PATTERN)),
|
| 136 | ];
|
| 137 |
|
| 138 | static IF_ELSE: [(Input, Action); 2] = [(Keyword("if"), SetState(&INIT)), (ConsumeBrace, DecDepth)];
|
| 139 | static IF_THEN: [(Input, Action); 2] =
|
| 140 | [(Keyword("else"), SetState(&IF_ELSE)), (Otherwise, DecDepth)];
|
| 141 |
|
| 142 | static METHOD: [(Input, Action); 1] = [(ExpectTurbofish, SetState(&POSTFIX))];
|
| 143 |
|
| 144 | static PATH: [(Input, Action); 4] = [
|
| 145 | (Punct("!="), SetState(&INIT)),
|
| 146 | (Punct("!"), SetState(&INIT)),
|
| 147 | (ConsumeNestedBrace, SetState(&IF_THEN)),
|
| 148 | (Otherwise, SetState(&POSTFIX)),
|
| 149 | ];
|
| 150 |
|
| 151 | static 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 |
|
| 169 | static 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 |
|
| 178 | static RAW: [(Input, Action); 3] = [
|
| 179 | (Keyword("const"), SetState(&INIT)),
|
| 180 | (Keyword("mut"), SetState(&INIT)),
|
| 181 | (Otherwise, SetState(&POSTFIX)),
|
| 182 | ];
|
| 183 |
|
| 184 | static REFERENCE: [(Input, Action); 3] = [
|
| 185 | (Keyword("mut"), SetState(&INIT)),
|
| 186 | (Keyword("raw"), SetState(&RAW)),
|
| 187 | (Otherwise, SetState(&INIT)),
|
| 188 | ];
|
| 189 |
|
| 190 | static RETURN: [(Input, Action); 2] = [
|
| 191 | (CanBeginExpr, SetState(&INIT)),
|
| 192 | (Otherwise, SetState(&POSTFIX)),
|
| 193 | ];
|
| 194 |
|
| 195 | pub(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 | }
|