|
1 |
| -use proc_macro2::Delimiter::{self, Brace, Bracket, Parenthesis}; |
| 1 | +use self::{Action::*, Input::*}; |
| 2 | +use proc_macro2::{Delimiter, Ident, Spacing, TokenTree}; |
2 | 3 | use syn::parse::{ParseStream, Result};
|
3 |
| -use syn::{ |
4 |
| - token, AngleBracketedGenericArguments, BinOp, ExprPath, Lifetime, Lit, LitFloat, Member, Token, |
5 |
| - Type, UnOp, |
6 |
| -}; |
| 4 | +use syn::{AngleBracketedGenericArguments, BinOp, Expr, ExprPath, Lifetime, Lit, Token, Type}; |
7 | 5 |
|
8 |
| -pub(crate) fn scan_expr(input: ParseStream) -> Result<()> { |
9 |
| - let consume = |delimiter: Delimiter| { |
10 |
| - Result::unwrap(input.step(|cursor| match cursor.group(delimiter) { |
11 |
| - Some((_inside, _span, rest)) => Ok((true, rest)), |
12 |
| - None => Ok((false, *cursor)), |
13 |
| - })) |
14 |
| - }; |
15 |
| - |
16 |
| - macro_rules! consume { |
17 |
| - [$token:tt] => { |
18 |
| - input.parse::<Option<Token![$token]>>().unwrap().is_some() |
19 |
| - }; |
20 |
| - } |
| 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 | +]; |
21 | 129 |
|
22 |
| - let mut initial = true; |
| 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(); |
23 | 194 | let mut depth = 0usize;
|
24 |
| - loop { |
25 |
| - if initial { |
26 |
| - if consume![&] { |
27 |
| - initial = consume![mut] || !consume![raw] || consume![const] || consume![mut]; |
28 |
| - } else if consume![if] || consume![match] || consume![while] { |
29 |
| - depth += 1; |
30 |
| - } else if input.parse::<Option<Lit>>()?.is_some() |
31 |
| - || (consume(Brace) || consume(Bracket) || consume(Parenthesis)) |
32 |
| - || (consume![async] || consume![const] || consume![loop] || consume![unsafe]) |
33 |
| - && (consume(Brace) || break) |
34 |
| - { |
35 |
| - initial = false; |
36 |
| - } else if consume![let] { |
37 |
| - while !consume![=] { |
38 |
| - if !((consume![|] || consume![ref] || consume![mut] || consume![@]) |
39 |
| - || (consume![!] || input.parse::<Option<Lit>>()?.is_some()) |
40 |
| - || (consume![..=] || consume![..] || consume![&] || consume![_]) |
41 |
| - || (consume(Brace) || consume(Bracket) || consume(Parenthesis))) |
42 |
| - { |
43 |
| - input.parse::<ExprPath>()?; |
| 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 | + } |
44 | 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 | + })? |
45 | 227 | }
|
46 |
| - } else if input.parse::<Option<Lifetime>>()?.is_some() && !consume![:] { |
47 |
| - break; |
48 |
| - } else if input.parse::<UnOp>().is_err() { |
49 |
| - input.parse::<ExprPath>()?; |
50 |
| - initial = consume![!] || depth == 0 && input.peek(token::Brace); |
51 |
| - } |
52 |
| - } else if input.is_empty() || input.peek(Token![,]) { |
53 |
| - return Ok(()); |
54 |
| - } else if depth > 0 && consume(Brace) { |
55 |
| - if consume![else] && !consume(Brace) { |
56 |
| - initial = consume![if] || break; |
57 |
| - } else { |
58 |
| - depth -= 1; |
59 |
| - } |
60 |
| - } else if input.parse::<BinOp>().is_ok() || (consume![..] | consume![=]) { |
61 |
| - initial = true; |
62 |
| - } else if consume![.] { |
63 |
| - if input.parse::<Option<LitFloat>>()?.is_none() |
64 |
| - && (matches!(input.parse()?, Member::Named(_)) && input.peek(Token![::])) |
65 |
| - { |
66 |
| - input.parse::<AngleBracketedGenericArguments>()?; |
| 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; |
67 | 260 | }
|
68 |
| - } else if consume![as] { |
69 |
| - input.parse::<Type>()?; |
70 |
| - } else if !(consume(Brace) || consume(Bracket) || consume(Parenthesis)) { |
71 |
| - break; |
72 | 261 | }
|
| 262 | + return Err(input.error("unsupported expression")); |
73 | 263 | }
|
74 |
| - |
75 |
| - Err(input.error("unsupported expression")) |
76 | 264 | }
|
0 commit comments