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