xref: /linux/rust/syn/scan_expr.rs (revision 808c999fc9e7c366fd47da564e69d579c1dc8279)
1 use self::{Action::*, Input::*};
2 use proc_macro2::{Delimiter, Ident, Spacing, TokenTree};
3 use syn::parse::{ParseStream, Result};
4 use syn::{AngleBracketedGenericArguments, BinOp, Expr, ExprPath, Lifetime, Lit, Token, Type};
5 
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); 7] = [
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     (ConsumeIdent, SetState(&CLOSURE)),
103 ];
104 
105 static CLOSURE_ARGS: [(Input, Action); 2] = [
106     (Punct("|"), SetState(&CLOSURE_RET)),
107     (ConsumeAny, SetState(&CLOSURE_ARGS)),
108 ];
109 
110 static CLOSURE_RET: [(Input, Action); 2] = [
111     (Punct("->"), SetState(&[(ExpectType, SetState(&BLOCK))])),
112     (Otherwise, SetState(&INIT)),
113 ];
114 
115 static CONST: [(Input, Action); 2] = [
116     (Punct("|"), SetState(&CLOSURE_ARGS)),
117     (ConsumeBrace, SetState(&POSTFIX)),
118 ];
119 
120 static CONTINUE: [(Input, Action); 2] = [
121     (ConsumeLifetime, SetState(&POSTFIX)),
122     (Otherwise, SetState(&POSTFIX)),
123 ];
124 
125 static DOT: [(Input, Action); 3] = [
126     (Keyword("await"), SetState(&POSTFIX)),
127     (ConsumeIdent, SetState(&METHOD)),
128     (ConsumeLiteral, SetState(&POSTFIX)),
129 ];
130 
131 static FOR: [(Input, Action); 2] = [
132     (Punct("<"), SetState(&CLOSURE)),
133     (Otherwise, SetState(&PATTERN)),
134 ];
135 
136 static IF_ELSE: [(Input, Action); 2] = [(Keyword("if"), SetState(&INIT)), (ConsumeBrace, DecDepth)];
137 static IF_THEN: [(Input, Action); 2] =
138     [(Keyword("else"), SetState(&IF_ELSE)), (Otherwise, DecDepth)];
139 
140 static METHOD: [(Input, Action); 1] = [(ExpectTurbofish, SetState(&POSTFIX))];
141 
142 static PATH: [(Input, Action); 4] = [
143     (Punct("!="), SetState(&INIT)),
144     (Punct("!"), SetState(&INIT)),
145     (ConsumeNestedBrace, SetState(&IF_THEN)),
146     (Otherwise, SetState(&POSTFIX)),
147 ];
148 
149 static PATTERN: [(Input, Action); 15] = [
150     (ConsumeDelimiter, SetState(&PATTERN)),
151     (Keyword("box"), SetState(&PATTERN)),
152     (Keyword("in"), IncDepth),
153     (Keyword("mut"), SetState(&PATTERN)),
154     (Keyword("ref"), SetState(&PATTERN)),
155     (Keyword("_"), SetState(&PATTERN)),
156     (Punct("!"), SetState(&PATTERN)),
157     (Punct("&"), SetState(&PATTERN)),
158     (Punct("..="), SetState(&PATTERN)),
159     (Punct(".."), SetState(&PATTERN)),
160     (Punct("="), SetState(&INIT)),
161     (Punct("@"), SetState(&PATTERN)),
162     (Punct("|"), SetState(&PATTERN)),
163     (ConsumeLiteral, SetState(&PATTERN)),
164     (ExpectPath, SetState(&PATTERN)),
165 ];
166 
167 static RANGE: [(Input, Action); 6] = [
168     (Punct("..="), SetState(&INIT)),
169     (Punct(".."), SetState(&RANGE)),
170     (Punct("."), SetState(&DOT)),
171     (ConsumeNestedBrace, SetState(&IF_THEN)),
172     (Empty, Finish),
173     (Otherwise, SetState(&INIT)),
174 ];
175 
176 static RAW: [(Input, Action); 3] = [
177     (Keyword("const"), SetState(&INIT)),
178     (Keyword("mut"), SetState(&INIT)),
179     (Otherwise, SetState(&POSTFIX)),
180 ];
181 
182 static REFERENCE: [(Input, Action); 3] = [
183     (Keyword("mut"), SetState(&INIT)),
184     (Keyword("raw"), SetState(&RAW)),
185     (Otherwise, SetState(&INIT)),
186 ];
187 
188 static RETURN: [(Input, Action); 2] = [
189     (CanBeginExpr, SetState(&INIT)),
190     (Otherwise, SetState(&POSTFIX)),
191 ];
192 
193 pub(crate) fn scan_expr(input: ParseStream) -> Result<()> {
194     let mut state = INIT.as_slice();
195     let mut depth = 0usize;
196     'table: loop {
197         for rule in state {
198             if match rule.0 {
199                 Input::Keyword(expected) => input.step(|cursor| match cursor.ident() {
200                     Some((ident, rest)) if ident == expected => Ok((true, rest)),
201                     _ => Ok((false, *cursor)),
202                 })?,
203                 Input::Punct(expected) => input.step(|cursor| {
204                     let begin = *cursor;
205                     let mut cursor = begin;
206                     for (i, ch) in expected.chars().enumerate() {
207                         match cursor.punct() {
208                             Some((punct, _)) if punct.as_char() != ch => break,
209                             Some((_, rest)) if i == expected.len() - 1 => {
210                                 return Ok((true, rest));
211                             }
212                             Some((punct, rest)) if punct.spacing() == Spacing::Joint => {
213                                 cursor = rest;
214                             }
215                             _ => break,
216                         }
217                     }
218                     Ok((false, begin))
219                 })?,
220                 Input::ConsumeAny => input.parse::<Option<TokenTree>>()?.is_some(),
221                 Input::ConsumeBinOp => input.parse::<BinOp>().is_ok(),
222                 Input::ConsumeBrace | Input::ConsumeNestedBrace => {
223                     (matches!(rule.0, Input::ConsumeBrace) || depth > 0)
224                         && input.step(|cursor| match cursor.group(Delimiter::Brace) {
225                             Some((_inside, _span, rest)) => Ok((true, rest)),
226                             None => Ok((false, *cursor)),
227                         })?
228                 }
229                 Input::ConsumeDelimiter => input.step(|cursor| match cursor.any_group() {
230                     Some((_inside, _delimiter, _span, rest)) => Ok((true, rest)),
231                     None => Ok((false, *cursor)),
232                 })?,
233                 Input::ConsumeIdent => input.parse::<Option<Ident>>()?.is_some(),
234                 Input::ConsumeLifetime => input.parse::<Option<Lifetime>>()?.is_some(),
235                 Input::ConsumeLiteral => input.parse::<Option<Lit>>()?.is_some(),
236                 Input::ExpectPath => {
237                     input.parse::<ExprPath>()?;
238                     true
239                 }
240                 Input::ExpectTurbofish => {
241                     if input.peek(Token![::]) {
242                         input.parse::<AngleBracketedGenericArguments>()?;
243                     }
244                     true
245                 }
246                 Input::ExpectType => {
247                     Type::without_plus(input)?;
248                     true
249                 }
250                 Input::CanBeginExpr => Expr::peek(input),
251                 Input::Otherwise => true,
252                 Input::Empty => input.is_empty() || input.peek(Token![,]),
253             } {
254                 state = match rule.1 {
255                     Action::SetState(next) => next,
256                     Action::IncDepth => (depth += 1, &INIT).1,
257                     Action::DecDepth => (depth -= 1, &POSTFIX).1,
258                     Action::Finish => return if depth == 0 { Ok(()) } else { break },
259                 };
260                 continue 'table;
261             }
262         }
263         return Err(input.error("unsupported expression"));
264     }
265 }
266