Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/syn/scan_expr.rs
38271 views
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
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
269