File Index
Files and directories
Sign in
FILE

scan_expr.rs

File preview with syntax highlighting.

linux-6.19.14/rust/syn/scan_expr.rs RUST
  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}
~/ Read-only file preview.