thiserror_impl/
scan_expr.rs

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