1 // SPDX-License-Identifier: Apache-2.0 OR MIT
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
scan_expr(input: ParseStream) -> Result<()>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 }
268