1*69942c0aSMiguel Ojeda // SPDX-License-Identifier: Apache-2.0 OR MIT
2*69942c0aSMiguel Ojeda
3808c999fSMiguel Ojeda use self::{Action::*, Input::*};
4808c999fSMiguel Ojeda use proc_macro2::{Delimiter, Ident, Spacing, TokenTree};
5808c999fSMiguel Ojeda use syn::parse::{ParseStream, Result};
6808c999fSMiguel Ojeda use syn::{AngleBracketedGenericArguments, BinOp, Expr, ExprPath, Lifetime, Lit, Token, Type};
7808c999fSMiguel Ojeda
8808c999fSMiguel Ojeda enum Input {
9808c999fSMiguel Ojeda Keyword(&'static str),
10808c999fSMiguel Ojeda Punct(&'static str),
11808c999fSMiguel Ojeda ConsumeAny,
12808c999fSMiguel Ojeda ConsumeBinOp,
13808c999fSMiguel Ojeda ConsumeBrace,
14808c999fSMiguel Ojeda ConsumeDelimiter,
15808c999fSMiguel Ojeda ConsumeIdent,
16808c999fSMiguel Ojeda ConsumeLifetime,
17808c999fSMiguel Ojeda ConsumeLiteral,
18808c999fSMiguel Ojeda ConsumeNestedBrace,
19808c999fSMiguel Ojeda ExpectPath,
20808c999fSMiguel Ojeda ExpectTurbofish,
21808c999fSMiguel Ojeda ExpectType,
22808c999fSMiguel Ojeda CanBeginExpr,
23808c999fSMiguel Ojeda Otherwise,
24808c999fSMiguel Ojeda Empty,
25808c999fSMiguel Ojeda }
26808c999fSMiguel Ojeda
27808c999fSMiguel Ojeda enum Action {
28808c999fSMiguel Ojeda SetState(&'static [(Input, Action)]),
29808c999fSMiguel Ojeda IncDepth,
30808c999fSMiguel Ojeda DecDepth,
31808c999fSMiguel Ojeda Finish,
32808c999fSMiguel Ojeda }
33808c999fSMiguel Ojeda
34808c999fSMiguel Ojeda static INIT: [(Input, Action); 28] = [
35808c999fSMiguel Ojeda (ConsumeDelimiter, SetState(&POSTFIX)),
36808c999fSMiguel Ojeda (Keyword("async"), SetState(&ASYNC)),
37808c999fSMiguel Ojeda (Keyword("break"), SetState(&BREAK_LABEL)),
38808c999fSMiguel Ojeda (Keyword("const"), SetState(&CONST)),
39808c999fSMiguel Ojeda (Keyword("continue"), SetState(&CONTINUE)),
40808c999fSMiguel Ojeda (Keyword("for"), SetState(&FOR)),
41808c999fSMiguel Ojeda (Keyword("if"), IncDepth),
42808c999fSMiguel Ojeda (Keyword("let"), SetState(&PATTERN)),
43808c999fSMiguel Ojeda (Keyword("loop"), SetState(&BLOCK)),
44808c999fSMiguel Ojeda (Keyword("match"), IncDepth),
45808c999fSMiguel Ojeda (Keyword("move"), SetState(&CLOSURE)),
46808c999fSMiguel Ojeda (Keyword("return"), SetState(&RETURN)),
47808c999fSMiguel Ojeda (Keyword("static"), SetState(&CLOSURE)),
48808c999fSMiguel Ojeda (Keyword("unsafe"), SetState(&BLOCK)),
49808c999fSMiguel Ojeda (Keyword("while"), IncDepth),
50808c999fSMiguel Ojeda (Keyword("yield"), SetState(&RETURN)),
51808c999fSMiguel Ojeda (Keyword("_"), SetState(&POSTFIX)),
52808c999fSMiguel Ojeda (Punct("!"), SetState(&INIT)),
53808c999fSMiguel Ojeda (Punct("#"), SetState(&[(ConsumeDelimiter, SetState(&INIT))])),
54808c999fSMiguel Ojeda (Punct("&"), SetState(&REFERENCE)),
55808c999fSMiguel Ojeda (Punct("*"), SetState(&INIT)),
56808c999fSMiguel Ojeda (Punct("-"), SetState(&INIT)),
57808c999fSMiguel Ojeda (Punct("..="), SetState(&INIT)),
58808c999fSMiguel Ojeda (Punct(".."), SetState(&RANGE)),
59808c999fSMiguel Ojeda (Punct("|"), SetState(&CLOSURE_ARGS)),
60808c999fSMiguel Ojeda (ConsumeLifetime, SetState(&[(Punct(":"), SetState(&INIT))])),
61808c999fSMiguel Ojeda (ConsumeLiteral, SetState(&POSTFIX)),
62808c999fSMiguel Ojeda (ExpectPath, SetState(&PATH)),
63808c999fSMiguel Ojeda ];
64808c999fSMiguel Ojeda
65808c999fSMiguel Ojeda static POSTFIX: [(Input, Action); 10] = [
66808c999fSMiguel Ojeda (Keyword("as"), SetState(&[(ExpectType, SetState(&POSTFIX))])),
67808c999fSMiguel Ojeda (Punct("..="), SetState(&INIT)),
68808c999fSMiguel Ojeda (Punct(".."), SetState(&RANGE)),
69808c999fSMiguel Ojeda (Punct("."), SetState(&DOT)),
70808c999fSMiguel Ojeda (Punct("?"), SetState(&POSTFIX)),
71808c999fSMiguel Ojeda (ConsumeBinOp, SetState(&INIT)),
72808c999fSMiguel Ojeda (Punct("="), SetState(&INIT)),
73808c999fSMiguel Ojeda (ConsumeNestedBrace, SetState(&IF_THEN)),
74808c999fSMiguel Ojeda (ConsumeDelimiter, SetState(&POSTFIX)),
75808c999fSMiguel Ojeda (Empty, Finish),
76808c999fSMiguel Ojeda ];
77808c999fSMiguel Ojeda
78808c999fSMiguel Ojeda static ASYNC: [(Input, Action); 3] = [
79808c999fSMiguel Ojeda (Keyword("move"), SetState(&ASYNC)),
80808c999fSMiguel Ojeda (Punct("|"), SetState(&CLOSURE_ARGS)),
81808c999fSMiguel Ojeda (ConsumeBrace, SetState(&POSTFIX)),
82808c999fSMiguel Ojeda ];
83808c999fSMiguel Ojeda
84808c999fSMiguel Ojeda static BLOCK: [(Input, Action); 1] = [(ConsumeBrace, SetState(&POSTFIX))];
85808c999fSMiguel Ojeda
86808c999fSMiguel Ojeda static BREAK_LABEL: [(Input, Action); 2] = [
87808c999fSMiguel Ojeda (ConsumeLifetime, SetState(&BREAK_VALUE)),
88808c999fSMiguel Ojeda (Otherwise, SetState(&BREAK_VALUE)),
89808c999fSMiguel Ojeda ];
90808c999fSMiguel Ojeda
91808c999fSMiguel Ojeda static BREAK_VALUE: [(Input, Action); 3] = [
92808c999fSMiguel Ojeda (ConsumeNestedBrace, SetState(&IF_THEN)),
93808c999fSMiguel Ojeda (CanBeginExpr, SetState(&INIT)),
94808c999fSMiguel Ojeda (Otherwise, SetState(&POSTFIX)),
95808c999fSMiguel Ojeda ];
96808c999fSMiguel Ojeda
97808c999fSMiguel Ojeda static CLOSURE: [(Input, Action); 7] = [
98808c999fSMiguel Ojeda (Keyword("async"), SetState(&CLOSURE)),
99808c999fSMiguel Ojeda (Keyword("move"), SetState(&CLOSURE)),
100808c999fSMiguel Ojeda (Punct(","), SetState(&CLOSURE)),
101808c999fSMiguel Ojeda (Punct(">"), SetState(&CLOSURE)),
102808c999fSMiguel Ojeda (Punct("|"), SetState(&CLOSURE_ARGS)),
103808c999fSMiguel Ojeda (ConsumeLifetime, SetState(&CLOSURE)),
104808c999fSMiguel Ojeda (ConsumeIdent, SetState(&CLOSURE)),
105808c999fSMiguel Ojeda ];
106808c999fSMiguel Ojeda
107808c999fSMiguel Ojeda static CLOSURE_ARGS: [(Input, Action); 2] = [
108808c999fSMiguel Ojeda (Punct("|"), SetState(&CLOSURE_RET)),
109808c999fSMiguel Ojeda (ConsumeAny, SetState(&CLOSURE_ARGS)),
110808c999fSMiguel Ojeda ];
111808c999fSMiguel Ojeda
112808c999fSMiguel Ojeda static CLOSURE_RET: [(Input, Action); 2] = [
113808c999fSMiguel Ojeda (Punct("->"), SetState(&[(ExpectType, SetState(&BLOCK))])),
114808c999fSMiguel Ojeda (Otherwise, SetState(&INIT)),
115808c999fSMiguel Ojeda ];
116808c999fSMiguel Ojeda
117808c999fSMiguel Ojeda static CONST: [(Input, Action); 2] = [
118808c999fSMiguel Ojeda (Punct("|"), SetState(&CLOSURE_ARGS)),
119808c999fSMiguel Ojeda (ConsumeBrace, SetState(&POSTFIX)),
120808c999fSMiguel Ojeda ];
121808c999fSMiguel Ojeda
122808c999fSMiguel Ojeda static CONTINUE: [(Input, Action); 2] = [
123808c999fSMiguel Ojeda (ConsumeLifetime, SetState(&POSTFIX)),
124808c999fSMiguel Ojeda (Otherwise, SetState(&POSTFIX)),
125808c999fSMiguel Ojeda ];
126808c999fSMiguel Ojeda
127808c999fSMiguel Ojeda static DOT: [(Input, Action); 3] = [
128808c999fSMiguel Ojeda (Keyword("await"), SetState(&POSTFIX)),
129808c999fSMiguel Ojeda (ConsumeIdent, SetState(&METHOD)),
130808c999fSMiguel Ojeda (ConsumeLiteral, SetState(&POSTFIX)),
131808c999fSMiguel Ojeda ];
132808c999fSMiguel Ojeda
133808c999fSMiguel Ojeda static FOR: [(Input, Action); 2] = [
134808c999fSMiguel Ojeda (Punct("<"), SetState(&CLOSURE)),
135808c999fSMiguel Ojeda (Otherwise, SetState(&PATTERN)),
136808c999fSMiguel Ojeda ];
137808c999fSMiguel Ojeda
138808c999fSMiguel Ojeda static IF_ELSE: [(Input, Action); 2] = [(Keyword("if"), SetState(&INIT)), (ConsumeBrace, DecDepth)];
139808c999fSMiguel Ojeda static IF_THEN: [(Input, Action); 2] =
140808c999fSMiguel Ojeda [(Keyword("else"), SetState(&IF_ELSE)), (Otherwise, DecDepth)];
141808c999fSMiguel Ojeda
142808c999fSMiguel Ojeda static METHOD: [(Input, Action); 1] = [(ExpectTurbofish, SetState(&POSTFIX))];
143808c999fSMiguel Ojeda
144808c999fSMiguel Ojeda static PATH: [(Input, Action); 4] = [
145808c999fSMiguel Ojeda (Punct("!="), SetState(&INIT)),
146808c999fSMiguel Ojeda (Punct("!"), SetState(&INIT)),
147808c999fSMiguel Ojeda (ConsumeNestedBrace, SetState(&IF_THEN)),
148808c999fSMiguel Ojeda (Otherwise, SetState(&POSTFIX)),
149808c999fSMiguel Ojeda ];
150808c999fSMiguel Ojeda
151808c999fSMiguel Ojeda static PATTERN: [(Input, Action); 15] = [
152808c999fSMiguel Ojeda (ConsumeDelimiter, SetState(&PATTERN)),
153808c999fSMiguel Ojeda (Keyword("box"), SetState(&PATTERN)),
154808c999fSMiguel Ojeda (Keyword("in"), IncDepth),
155808c999fSMiguel Ojeda (Keyword("mut"), SetState(&PATTERN)),
156808c999fSMiguel Ojeda (Keyword("ref"), SetState(&PATTERN)),
157808c999fSMiguel Ojeda (Keyword("_"), SetState(&PATTERN)),
158808c999fSMiguel Ojeda (Punct("!"), SetState(&PATTERN)),
159808c999fSMiguel Ojeda (Punct("&"), SetState(&PATTERN)),
160808c999fSMiguel Ojeda (Punct("..="), SetState(&PATTERN)),
161808c999fSMiguel Ojeda (Punct(".."), SetState(&PATTERN)),
162808c999fSMiguel Ojeda (Punct("="), SetState(&INIT)),
163808c999fSMiguel Ojeda (Punct("@"), SetState(&PATTERN)),
164808c999fSMiguel Ojeda (Punct("|"), SetState(&PATTERN)),
165808c999fSMiguel Ojeda (ConsumeLiteral, SetState(&PATTERN)),
166808c999fSMiguel Ojeda (ExpectPath, SetState(&PATTERN)),
167808c999fSMiguel Ojeda ];
168808c999fSMiguel Ojeda
169808c999fSMiguel Ojeda static RANGE: [(Input, Action); 6] = [
170808c999fSMiguel Ojeda (Punct("..="), SetState(&INIT)),
171808c999fSMiguel Ojeda (Punct(".."), SetState(&RANGE)),
172808c999fSMiguel Ojeda (Punct("."), SetState(&DOT)),
173808c999fSMiguel Ojeda (ConsumeNestedBrace, SetState(&IF_THEN)),
174808c999fSMiguel Ojeda (Empty, Finish),
175808c999fSMiguel Ojeda (Otherwise, SetState(&INIT)),
176808c999fSMiguel Ojeda ];
177808c999fSMiguel Ojeda
178808c999fSMiguel Ojeda static RAW: [(Input, Action); 3] = [
179808c999fSMiguel Ojeda (Keyword("const"), SetState(&INIT)),
180808c999fSMiguel Ojeda (Keyword("mut"), SetState(&INIT)),
181808c999fSMiguel Ojeda (Otherwise, SetState(&POSTFIX)),
182808c999fSMiguel Ojeda ];
183808c999fSMiguel Ojeda
184808c999fSMiguel Ojeda static REFERENCE: [(Input, Action); 3] = [
185808c999fSMiguel Ojeda (Keyword("mut"), SetState(&INIT)),
186808c999fSMiguel Ojeda (Keyword("raw"), SetState(&RAW)),
187808c999fSMiguel Ojeda (Otherwise, SetState(&INIT)),
188808c999fSMiguel Ojeda ];
189808c999fSMiguel Ojeda
190808c999fSMiguel Ojeda static RETURN: [(Input, Action); 2] = [
191808c999fSMiguel Ojeda (CanBeginExpr, SetState(&INIT)),
192808c999fSMiguel Ojeda (Otherwise, SetState(&POSTFIX)),
193808c999fSMiguel Ojeda ];
194808c999fSMiguel Ojeda
scan_expr(input: ParseStream) -> Result<()>195808c999fSMiguel Ojeda pub(crate) fn scan_expr(input: ParseStream) -> Result<()> {
196808c999fSMiguel Ojeda let mut state = INIT.as_slice();
197808c999fSMiguel Ojeda let mut depth = 0usize;
198808c999fSMiguel Ojeda 'table: loop {
199808c999fSMiguel Ojeda for rule in state {
200808c999fSMiguel Ojeda if match rule.0 {
201808c999fSMiguel Ojeda Input::Keyword(expected) => input.step(|cursor| match cursor.ident() {
202808c999fSMiguel Ojeda Some((ident, rest)) if ident == expected => Ok((true, rest)),
203808c999fSMiguel Ojeda _ => Ok((false, *cursor)),
204808c999fSMiguel Ojeda })?,
205808c999fSMiguel Ojeda Input::Punct(expected) => input.step(|cursor| {
206808c999fSMiguel Ojeda let begin = *cursor;
207808c999fSMiguel Ojeda let mut cursor = begin;
208808c999fSMiguel Ojeda for (i, ch) in expected.chars().enumerate() {
209808c999fSMiguel Ojeda match cursor.punct() {
210808c999fSMiguel Ojeda Some((punct, _)) if punct.as_char() != ch => break,
211808c999fSMiguel Ojeda Some((_, rest)) if i == expected.len() - 1 => {
212808c999fSMiguel Ojeda return Ok((true, rest));
213808c999fSMiguel Ojeda }
214808c999fSMiguel Ojeda Some((punct, rest)) if punct.spacing() == Spacing::Joint => {
215808c999fSMiguel Ojeda cursor = rest;
216808c999fSMiguel Ojeda }
217808c999fSMiguel Ojeda _ => break,
218808c999fSMiguel Ojeda }
219808c999fSMiguel Ojeda }
220808c999fSMiguel Ojeda Ok((false, begin))
221808c999fSMiguel Ojeda })?,
222808c999fSMiguel Ojeda Input::ConsumeAny => input.parse::<Option<TokenTree>>()?.is_some(),
223808c999fSMiguel Ojeda Input::ConsumeBinOp => input.parse::<BinOp>().is_ok(),
224808c999fSMiguel Ojeda Input::ConsumeBrace | Input::ConsumeNestedBrace => {
225808c999fSMiguel Ojeda (matches!(rule.0, Input::ConsumeBrace) || depth > 0)
226808c999fSMiguel Ojeda && input.step(|cursor| match cursor.group(Delimiter::Brace) {
227808c999fSMiguel Ojeda Some((_inside, _span, rest)) => Ok((true, rest)),
228808c999fSMiguel Ojeda None => Ok((false, *cursor)),
229808c999fSMiguel Ojeda })?
230808c999fSMiguel Ojeda }
231808c999fSMiguel Ojeda Input::ConsumeDelimiter => input.step(|cursor| match cursor.any_group() {
232808c999fSMiguel Ojeda Some((_inside, _delimiter, _span, rest)) => Ok((true, rest)),
233808c999fSMiguel Ojeda None => Ok((false, *cursor)),
234808c999fSMiguel Ojeda })?,
235808c999fSMiguel Ojeda Input::ConsumeIdent => input.parse::<Option<Ident>>()?.is_some(),
236808c999fSMiguel Ojeda Input::ConsumeLifetime => input.parse::<Option<Lifetime>>()?.is_some(),
237808c999fSMiguel Ojeda Input::ConsumeLiteral => input.parse::<Option<Lit>>()?.is_some(),
238808c999fSMiguel Ojeda Input::ExpectPath => {
239808c999fSMiguel Ojeda input.parse::<ExprPath>()?;
240808c999fSMiguel Ojeda true
241808c999fSMiguel Ojeda }
242808c999fSMiguel Ojeda Input::ExpectTurbofish => {
243808c999fSMiguel Ojeda if input.peek(Token![::]) {
244808c999fSMiguel Ojeda input.parse::<AngleBracketedGenericArguments>()?;
245808c999fSMiguel Ojeda }
246808c999fSMiguel Ojeda true
247808c999fSMiguel Ojeda }
248808c999fSMiguel Ojeda Input::ExpectType => {
249808c999fSMiguel Ojeda Type::without_plus(input)?;
250808c999fSMiguel Ojeda true
251808c999fSMiguel Ojeda }
252808c999fSMiguel Ojeda Input::CanBeginExpr => Expr::peek(input),
253808c999fSMiguel Ojeda Input::Otherwise => true,
254808c999fSMiguel Ojeda Input::Empty => input.is_empty() || input.peek(Token![,]),
255808c999fSMiguel Ojeda } {
256808c999fSMiguel Ojeda state = match rule.1 {
257808c999fSMiguel Ojeda Action::SetState(next) => next,
258808c999fSMiguel Ojeda Action::IncDepth => (depth += 1, &INIT).1,
259808c999fSMiguel Ojeda Action::DecDepth => (depth -= 1, &POSTFIX).1,
260808c999fSMiguel Ojeda Action::Finish => return if depth == 0 { Ok(()) } else { break },
261808c999fSMiguel Ojeda };
262808c999fSMiguel Ojeda continue 'table;
263808c999fSMiguel Ojeda }
264808c999fSMiguel Ojeda }
265808c999fSMiguel Ojeda return Err(input.error("unsupported expression"));
266808c999fSMiguel Ojeda }
267808c999fSMiguel Ojeda }
268