Coverage Report

Created: 2026-04-12 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/proc-macro2-1.0.106/src/parse.rs
Line
Count
Source
1
use crate::fallback::{
2
    self, is_ident_continue, is_ident_start, Group, Ident, LexError, Literal, Span, TokenStream,
3
    TokenStreamBuilder,
4
};
5
use crate::{Delimiter, Punct, Spacing, TokenTree};
6
use alloc::borrow::ToOwned as _;
7
use alloc::string::ToString as _;
8
use alloc::vec::Vec;
9
use core::char;
10
use core::str::{Bytes, CharIndices, Chars};
11
12
#[derive(Copy, Clone, Eq, PartialEq)]
13
pub(crate) struct Cursor<'a> {
14
    pub(crate) rest: &'a str,
15
    #[cfg(span_locations)]
16
    pub(crate) off: u32,
17
}
18
19
impl<'a> Cursor<'a> {
20
25.2M
    pub(crate) fn advance(&self, bytes: usize) -> Cursor<'a> {
21
25.2M
        let (_front, rest) = self.rest.split_at(bytes);
22
25.2M
        Cursor {
23
25.2M
            rest,
24
25.2M
            #[cfg(span_locations)]
25
25.2M
            off: self.off + _front.chars().count() as u32,
26
25.2M
        }
27
25.2M
    }
28
29
219M
    pub(crate) fn starts_with(&self, s: &str) -> bool {
30
219M
        self.rest.starts_with(s)
31
219M
    }
32
33
1.90k
    pub(crate) fn starts_with_char(&self, ch: char) -> bool {
34
1.90k
        self.rest.starts_with(ch)
35
1.90k
    }
36
37
0
    pub(crate) fn starts_with_fn<Pattern>(&self, f: Pattern) -> bool
38
0
    where
39
0
        Pattern: FnMut(char) -> bool,
40
    {
41
0
        self.rest.starts_with(f)
42
0
    }
43
44
20.2M
    pub(crate) fn is_empty(&self) -> bool {
45
20.2M
        self.rest.is_empty()
46
20.2M
    }
47
48
5.10M
    fn len(&self) -> usize {
49
5.10M
        self.rest.len()
50
5.10M
    }
51
52
20.2M
    fn as_bytes(&self) -> &'a [u8] {
53
20.2M
        self.rest.as_bytes()
54
20.2M
    }
55
56
27.8M
    fn bytes(&self) -> Bytes<'a> {
57
27.8M
        self.rest.bytes()
58
27.8M
    }
59
60
28.8M
    fn chars(&self) -> Chars<'a> {
61
28.8M
        self.rest.chars()
62
28.8M
    }
63
64
727k
    fn char_indices(&self) -> CharIndices<'a> {
65
727k
        self.rest.char_indices()
66
727k
    }
67
68
78.5M
    fn parse(&self, tag: &str) -> Result<Cursor<'a>, Reject> {
69
78.5M
        if self.starts_with(tag) {
70
72.5k
            Ok(self.advance(tag.len()))
71
        } else {
72
78.5M
            Err(Reject)
73
        }
74
78.5M
    }
75
}
76
77
pub(crate) struct Reject;
78
type PResult<'a, O> = Result<(Cursor<'a>, O), Reject>;
79
80
18.9M
fn skip_whitespace(input: Cursor) -> Cursor {
81
18.9M
    let mut s = input;
82
83
20.2M
    while !s.is_empty() {
84
20.2M
        let byte = s.as_bytes()[0];
85
20.2M
        if byte == b'/' {
86
52.9k
            if s.starts_with("//")
87
16.0k
                && (!s.starts_with("///") || s.starts_with("////"))
88
15.4k
                && !s.starts_with("//!")
89
            {
90
1.16k
                let (cursor, _) = take_until_newline_or_eof(s);
91
1.16k
                s = cursor;
92
1.16k
                continue;
93
51.7k
            } else if s.starts_with("/**/") {
94
21
                s = s.advance(4);
95
21
                continue;
96
51.7k
            } else if s.starts_with("/*")
97
163
                && (!s.starts_with("/**") || s.starts_with("/***"))
98
86
                && !s.starts_with("/*!")
99
            {
100
76
                match block_comment(s) {
101
68
                    Ok((rest, _)) => {
102
68
                        s = rest;
103
68
                        continue;
104
                    }
105
8
                    Err(Reject) => return s,
106
                }
107
51.6k
            }
108
20.2M
        }
109
18.9M
        match byte {
110
20.1M
            b' ' | 0x09..=0x0d => {
111
1.31M
                s = s.advance(1);
112
1.31M
                continue;
113
            }
114
18.9M
            b if b.is_ascii() => {}
115
            _ => {
116
396
                let ch = s.chars().next().unwrap();
117
396
                if is_whitespace(ch) {
118
246
                    s = s.advance(ch.len_utf8());
119
246
                    continue;
120
150
                }
121
            }
122
        }
123
18.9M
        return s;
124
    }
125
165
    s
126
18.9M
}
127
128
163
fn block_comment(input: Cursor) -> PResult<&str> {
129
163
    if !input.starts_with("/*") {
130
0
        return Err(Reject);
131
163
    }
132
133
163
    let mut depth = 0usize;
134
163
    let bytes = input.as_bytes();
135
163
    let mut i = 0usize;
136
163
    let upper = bytes.len() - 1;
137
138
12.7M
    while i < upper {
139
12.7M
        if bytes[i] == b'/' && bytes[i + 1] == b'*' {
140
2.20M
            depth += 1;
141
2.20M
            i += 1; // eat '*'
142
10.4M
        } else if bytes[i] == b'*' && bytes[i + 1] == b'/' {
143
29.1k
            depth -= 1;
144
29.1k
            if depth == 0 {
145
140
                return Ok((input.advance(i + 2), &input.rest[..i + 2]));
146
29.0k
            }
147
29.0k
            i += 1; // eat '/'
148
10.4M
        }
149
12.7M
        i += 1;
150
    }
151
152
23
    Err(Reject)
153
163
}
154
155
396
fn is_whitespace(ch: char) -> bool {
156
    // Rust treats left-to-right mark and right-to-left mark as whitespace
157
396
    ch.is_whitespace() || ch == '\u{200e}' || ch == '\u{200f}'
158
396
}
159
160
2.19M
fn word_break(input: Cursor) -> Result<Cursor, Reject> {
161
2.19M
    match input.chars().next() {
162
2.19M
        Some(ch) if is_ident_continue(ch) => Err(Reject),
163
2.19M
        Some(_) | None => Ok(input),
164
    }
165
2.19M
}
166
167
// Rustc's representation of a macro expansion error in expression position or
168
// type position.
169
const ERROR: &str = "(/*ERROR*/)";
170
171
431
pub(crate) fn token_stream(mut input: Cursor) -> Result<TokenStream, LexError> {
172
431
    let mut tokens = TokenStreamBuilder::new();
173
431
    let mut stack = Vec::new();
174
175
    loop {
176
18.9M
        input = skip_whitespace(input);
177
178
18.9M
        if let Ok((rest, ())) = doc_comment(input, &mut tokens) {
179
14.9k
            input = rest;
180
14.9k
            continue;
181
18.9M
        }
182
183
        #[cfg(span_locations)]
184
        let lo = input.off;
185
186
18.9M
        let Some(first) = input.bytes().next() else {
187
165
            return match stack.last() {
188
149
                None => Ok(tokens.build()),
189
                #[cfg(span_locations)]
190
                Some((lo, _frame)) => Err(LexError {
191
                    span: Span { lo: *lo, hi: *lo },
192
                }),
193
                #[cfg(not(span_locations))]
194
16
                Some(_frame) => Err(LexError { span: Span {} }),
195
            };
196
        };
197
198
8.51M
        if let Some(open_delimiter) = match first {
199
2.60M
            b'(' if !input.starts_with(ERROR) => Some(Delimiter::Parenthesis),
200
5.90M
            b'[' => Some(Delimiter::Bracket),
201
2.20k
            b'{' => Some(Delimiter::Brace),
202
10.4M
            _ => None,
203
8.51M
        } {
204
8.51M
            input = input.advance(1);
205
8.51M
            let frame = (open_delimiter, tokens);
206
8.51M
            #[cfg(span_locations)]
207
8.51M
            let frame = (lo, frame);
208
8.51M
            stack.push(frame);
209
8.51M
            tokens = TokenStreamBuilder::new();
210
10.4M
        } else if let Some(close_delimiter) = match first {
211
541k
            b')' => Some(Delimiter::Parenthesis),
212
4.52k
            b']' => Some(Delimiter::Bracket),
213
1.91k
            b'}' => Some(Delimiter::Brace),
214
9.87M
            _ => None,
215
        } {
216
547k
            let Some(frame) = stack.pop() else {
217
8
                return Err(lex_error(input));
218
            };
219
            #[cfg(span_locations)]
220
            let (lo, frame) = frame;
221
547k
            let (open_delimiter, outer) = frame;
222
547k
            if open_delimiter != close_delimiter {
223
2
                return Err(lex_error(input));
224
547k
            }
225
547k
            input = input.advance(1);
226
547k
            let mut g = Group::new(open_delimiter, tokens.build());
227
547k
            g.set_span(Span {
228
547k
                #[cfg(span_locations)]
229
547k
                lo,
230
547k
                #[cfg(span_locations)]
231
547k
                hi: input.off,
232
547k
            });
233
547k
            tokens = outer;
234
547k
            tokens.push_token_from_parser(TokenTree::Group(crate::Group::_new_fallback(g)));
235
        } else {
236
9.87M
            let (rest, mut tt) = match leaf_token(input) {
237
9.87M
                Ok((rest, tt)) => (rest, tt),
238
256
                Err(Reject) => return Err(lex_error(input)),
239
            };
240
9.87M
            tt.set_span(crate::Span::_new_fallback(Span {
241
9.87M
                #[cfg(span_locations)]
242
9.87M
                lo,
243
9.87M
                #[cfg(span_locations)]
244
9.87M
                hi: rest.off,
245
9.87M
            }));
246
9.87M
            tokens.push_token_from_parser(tt);
247
9.87M
            input = rest;
248
        }
249
    }
250
431
}
251
252
266
fn lex_error(cursor: Cursor) -> LexError {
253
    #[cfg(not(span_locations))]
254
266
    let _ = cursor;
255
266
    LexError {
256
266
        span: Span {
257
266
            #[cfg(span_locations)]
258
266
            lo: cursor.off,
259
266
            #[cfg(span_locations)]
260
266
            hi: cursor.off,
261
266
        },
262
266
    }
263
266
}
264
265
9.87M
fn leaf_token(input: Cursor) -> PResult<TokenTree> {
266
9.87M
    if let Ok((input, l)) = literal(input) {
267
        // must be parsed before ident
268
2.25M
        Ok((input, TokenTree::Literal(crate::Literal::_new_fallback(l))))
269
7.61M
    } else if let Ok((input, p)) = punct(input) {
270
7.02M
        Ok((input, TokenTree::Punct(p)))
271
591k
    } else if let Ok((input, i)) = ident(input) {
272
591k
        Ok((input, TokenTree::Ident(i)))
273
404
    } else if input.starts_with(ERROR) {
274
148
        let rest = input.advance(ERROR.len());
275
148
        let repr = crate::Literal::_new_fallback(Literal::_new(ERROR.to_owned()));
276
148
        Ok((rest, TokenTree::Literal(repr)))
277
    } else {
278
256
        Err(Reject)
279
    }
280
9.87M
}
281
282
591k
fn ident(input: Cursor) -> PResult<crate::Ident> {
283
591k
    if [
284
591k
        "r\"", "r#\"", "r##", "b\"", "b\'", "br\"", "br#", "c\"", "cr\"", "cr#",
285
591k
    ]
286
591k
    .iter()
287
5.91M
    .any(|prefix| input.starts_with(prefix))
288
    {
289
70
        Err(Reject)
290
    } else {
291
591k
        ident_any(input)
292
    }
293
591k
}
294
295
592k
fn ident_any(input: Cursor) -> PResult<crate::Ident> {
296
592k
    let raw = input.starts_with("r#");
297
592k
    let rest = input.advance((raw as usize) << 1);
298
299
592k
    let (rest, sym) = ident_not_raw(rest)?;
300
301
591k
    if !raw {
302
590k
        let ident =
303
590k
            crate::Ident::_new_fallback(Ident::new_unchecked(sym, fallback::Span::call_site()));
304
590k
        return Ok((rest, ident));
305
1.12k
    }
306
307
1.12k
    match sym {
308
1.12k
        "_" | "super" | "self" | "Self" | "crate" => return Err(Reject),
309
1.12k
        _ => {}
310
    }
311
312
1.12k
    let ident =
313
1.12k
        crate::Ident::_new_fallback(Ident::new_raw_unchecked(sym, fallback::Span::call_site()));
314
1.12k
    Ok((rest, ident))
315
592k
}
316
317
653k
fn ident_not_raw(input: Cursor) -> PResult<&str> {
318
653k
    let mut chars = input.char_indices();
319
320
653k
    match chars.next() {
321
653k
        Some((_, ch)) if is_ident_start(ch) => {}
322
57.6k
        _ => return Err(Reject),
323
    }
324
325
596k
    let mut end = input.len();
326
18.8M
    for (i, ch) in chars {
327
18.8M
        if !is_ident_continue(ch) {
328
596k
            end = i;
329
596k
            break;
330
18.2M
        }
331
    }
332
333
596k
    Ok((input.advance(end), &input.rest[..end]))
334
653k
}
335
336
9.87M
pub(crate) fn literal(input: Cursor) -> PResult<Literal> {
337
9.87M
    let rest = literal_nocapture(input)?;
338
2.25M
    let end = input.len() - rest.len();
339
2.25M
    Ok((rest, Literal::_new(input.rest[..end].to_string())))
340
9.87M
}
341
342
9.87M
fn literal_nocapture(input: Cursor) -> Result<Cursor, Reject> {
343
9.87M
    if let Ok(ok) = string(input) {
344
56.9k
        Ok(ok)
345
9.81M
    } else if let Ok(ok) = byte_string(input) {
346
90
        Ok(ok)
347
9.81M
    } else if let Ok(ok) = c_string(input) {
348
99
        Ok(ok)
349
9.81M
    } else if let Ok(ok) = byte(input) {
350
14
        Ok(ok)
351
9.81M
    } else if let Ok(ok) = character(input) {
352
158
        Ok(ok)
353
9.81M
    } else if let Ok(ok) = float(input) {
354
919k
        Ok(ok)
355
8.89M
    } else if let Ok(ok) = int(input) {
356
1.27M
        Ok(ok)
357
    } else {
358
7.61M
        Err(Reject)
359
    }
360
9.87M
}
361
362
57.3k
fn literal_suffix(input: Cursor) -> Cursor {
363
57.3k
    match ident_not_raw(input) {
364
84
        Ok((input, _)) => input,
365
57.2k
        Err(Reject) => input,
366
    }
367
57.3k
}
368
369
9.87M
fn string(input: Cursor) -> Result<Cursor, Reject> {
370
9.87M
    if let Ok(input) = input.parse("\"") {
371
56.8k
        cooked_string(input)
372
9.81M
    } else if let Ok(input) = input.parse("r") {
373
13.3k
        raw_string(input)
374
    } else {
375
9.80M
        Err(Reject)
376
    }
377
9.87M
}
378
379
56.8k
fn cooked_string(mut input: Cursor) -> Result<Cursor, Reject> {
380
56.8k
    let mut chars = input.char_indices();
381
382
6.86M
    while let Some((i, ch)) = chars.next() {
383
6.86M
        match ch {
384
            '"' => {
385
56.8k
                let input = input.advance(i + 1);
386
56.8k
                return Ok(literal_suffix(input));
387
            }
388
741
            '\r' => match chars.next() {
389
736
                Some((_, '\n')) => {}
390
5
                _ => break,
391
            },
392
345
            '\\' => match chars.next() {
393
                Some((_, 'x')) => {
394
125
                    backslash_x_char(&mut chars)?;
395
                }
396
192
                Some((_, 'n' | 'r' | 't' | '\\' | '\'' | '"' | '0')) => {}
397
                Some((_, 'u')) => {
398
2
                    backslash_u(&mut chars)?;
399
                }
400
23
                Some((newline, ch @ ('\n' | '\r'))) => {
401
23
                    input = input.advance(newline + 1);
402
23
                    trailing_backslash(&mut input, ch as u8)?;
403
23
                    chars = input.char_indices();
404
                }
405
3
                _ => break,
406
            },
407
6.80M
            _ch => {}
408
        }
409
    }
410
16
    Err(Reject)
411
56.8k
}
412
413
13.3k
fn raw_string(input: Cursor) -> Result<Cursor, Reject> {
414
13.3k
    let (input, delimiter) = delimiter_of_raw_string(input)?;
415
135
    let mut bytes = input.bytes().enumerate();
416
4.17M
    while let Some((i, byte)) = bytes.next() {
417
5.23k
        match byte {
418
5.23k
            b'"' if input.rest[i + 1..].starts_with(delimiter) => {
419
129
                let rest = input.advance(i + 1 + delimiter.len());
420
129
                return Ok(literal_suffix(rest));
421
            }
422
3.25k
            b'\r' => match bytes.next() {
423
3.25k
                Some((_, b'\n')) => {}
424
1
                _ => break,
425
            },
426
4.16M
            _ => {}
427
        }
428
    }
429
6
    Err(Reject)
430
13.3k
}
431
432
9.81M
fn byte_string(input: Cursor) -> Result<Cursor, Reject> {
433
9.81M
    if let Ok(input) = input.parse("b\"") {
434
58
        cooked_byte_string(input)
435
9.81M
    } else if let Ok(input) = input.parse("br") {
436
662
        raw_byte_string(input)
437
    } else {
438
9.81M
        Err(Reject)
439
    }
440
9.81M
}
441
442
58
fn cooked_byte_string(mut input: Cursor) -> Result<Cursor, Reject> {
443
58
    let mut bytes = input.bytes().enumerate();
444
4.56M
    while let Some((offset, b)) = bytes.next() {
445
4.53M
        match b {
446
            b'"' => {
447
37
                let input = input.advance(offset + 1);
448
37
                return Ok(literal_suffix(input));
449
            }
450
28.2k
            b'\r' => match bytes.next() {
451
28.2k
                Some((_, b'\n')) => {}
452
1
                _ => break,
453
            },
454
189
            b'\\' => match bytes.next() {
455
                Some((_, b'x')) => {
456
27
                    backslash_x_byte(&mut bytes)?;
457
                }
458
154
                Some((_, b'n' | b'r' | b't' | b'\\' | b'0' | b'\'' | b'"')) => {}
459
8
                Some((newline, b @ (b'\n' | b'\r'))) => {
460
8
                    input = input.advance(newline + 1);
461
8
                    trailing_backslash(&mut input, b)?;
462
7
                    bytes = input.bytes().enumerate();
463
                }
464
0
                _ => break,
465
            },
466
4.53M
            b if b.is_ascii() => {}
467
3
            _ => break,
468
        }
469
    }
470
9
    Err(Reject)
471
58
}
472
473
14.5k
fn delimiter_of_raw_string(input: Cursor) -> PResult<&str> {
474
938k
    for (i, byte) in input.bytes().enumerate() {
475
938k
        match byte {
476
            b'"' => {
477
265
                if i > 255 {
478
                    // https://github.com/rust-lang/rust/pull/95251
479
2
                    return Err(Reject);
480
263
                }
481
263
                return Ok((input.advance(i + 1), &input.rest[..i]));
482
            }
483
924k
            b'#' => {}
484
14.3k
            _ => break,
485
        }
486
    }
487
14.3k
    Err(Reject)
488
14.5k
}
489
490
662
fn raw_byte_string(input: Cursor) -> Result<Cursor, Reject> {
491
662
    let (input, delimiter) = delimiter_of_raw_string(input)?;
492
60
    let mut bytes = input.bytes().enumerate();
493
2.97M
    while let Some((i, byte)) = bytes.next() {
494
129k
        match byte {
495
129k
            b'"' if input.rest[i + 1..].starts_with(delimiter) => {
496
53
                let rest = input.advance(i + 1 + delimiter.len());
497
53
                return Ok(literal_suffix(rest));
498
            }
499
204
            b'\r' => match bytes.next() {
500
202
                Some((_, b'\n')) => {}
501
2
                _ => break,
502
            },
503
2.97M
            other => {
504
2.97M
                if !other.is_ascii() {
505
1
                    break;
506
2.97M
                }
507
            }
508
        }
509
    }
510
7
    Err(Reject)
511
662
}
512
513
9.81M
fn c_string(input: Cursor) -> Result<Cursor, Reject> {
514
9.81M
    if let Ok(input) = input.parse("c\"") {
515
47
        cooked_c_string(input)
516
9.81M
    } else if let Ok(input) = input.parse("cr") {
517
587
        raw_c_string(input)
518
    } else {
519
9.81M
        Err(Reject)
520
    }
521
9.81M
}
522
523
587
fn raw_c_string(input: Cursor) -> Result<Cursor, Reject> {
524
587
    let (input, delimiter) = delimiter_of_raw_string(input)?;
525
68
    let mut bytes = input.bytes().enumerate();
526
1.44M
    while let Some((i, byte)) = bytes.next() {
527
269
        match byte {
528
269
            b'"' if input.rest[i + 1..].starts_with(delimiter) => {
529
59
                let rest = input.advance(i + 1 + delimiter.len());
530
59
                return Ok(literal_suffix(rest));
531
            }
532
12.6k
            b'\r' => match bytes.next() {
533
12.6k
                Some((_, b'\n')) => {}
534
0
                _ => break,
535
            },
536
6
            b'\0' => break,
537
1.43M
            _ => {}
538
        }
539
    }
540
9
    Err(Reject)
541
587
}
542
543
47
fn cooked_c_string(mut input: Cursor) -> Result<Cursor, Reject> {
544
47
    let mut chars = input.char_indices();
545
546
524k
    while let Some((i, ch)) = chars.next() {
547
524k
        match ch {
548
            '"' => {
549
40
                let input = input.advance(i + 1);
550
40
                return Ok(literal_suffix(input));
551
            }
552
2
            '\r' => match chars.next() {
553
0
                Some((_, '\n')) => {}
554
2
                _ => break,
555
            },
556
10
            '\\' => match chars.next() {
557
                Some((_, 'x')) => {
558
0
                    backslash_x_nonzero(&mut chars)?;
559
                }
560
1
                Some((_, 'n' | 'r' | 't' | '\\' | '\'' | '"')) => {}
561
                Some((_, 'u')) => {
562
0
                    if backslash_u(&mut chars)? == '\0' {
563
0
                        break;
564
0
                    }
565
                }
566
9
                Some((newline, ch @ ('\n' | '\r'))) => {
567
9
                    input = input.advance(newline + 1);
568
9
                    trailing_backslash(&mut input, ch as u8)?;
569
6
                    chars = input.char_indices();
570
                }
571
0
                _ => break,
572
            },
573
2
            '\0' => break,
574
524k
            _ch => {}
575
        }
576
    }
577
4
    Err(Reject)
578
47
}
579
580
9.81M
fn byte(input: Cursor) -> Result<Cursor, Reject> {
581
9.81M
    let input = input.parse("b'")?;
582
28
    let mut bytes = input.bytes().enumerate();
583
28
    let ok = match bytes.next().map(|(_, b)| b) {
584
10
        Some(b'\\') => match bytes.next().map(|(_, b)| b) {
585
6
            Some(b'x') => backslash_x_byte(&mut bytes).is_ok(),
586
3
            Some(b'n' | b'r' | b't' | b'\\' | b'0' | b'\'' | b'"') => true,
587
1
            _ => false,
588
        },
589
18
        b => b.is_some(),
590
    };
591
28
    if !ok {
592
1
        return Err(Reject);
593
27
    }
594
27
    let (offset, _) = bytes.next().ok_or(Reject)?;
595
23
    if !input.chars().as_str().is_char_boundary(offset) {
596
0
        return Err(Reject);
597
23
    }
598
23
    let input = input.advance(offset).parse("'")?;
599
14
    Ok(literal_suffix(input))
600
9.81M
}
601
602
9.81M
fn character(input: Cursor) -> Result<Cursor, Reject> {
603
9.81M
    let input = input.parse("'")?;
604
809
    let mut chars = input.char_indices();
605
809
    let ok = match chars.next().map(|(_, ch)| ch) {
606
21
        Some('\\') => match chars.next().map(|(_, ch)| ch) {
607
11
            Some('x') => backslash_x_char(&mut chars).is_ok(),
608
0
            Some('u') => backslash_u(&mut chars).is_ok(),
609
9
            Some('n' | 'r' | 't' | '\\' | '0' | '\'' | '"') => true,
610
1
            _ => false,
611
        },
612
788
        ch => ch.is_some(),
613
    };
614
809
    if !ok {
615
1
        return Err(Reject);
616
808
    }
617
808
    let (idx, _) = chars.next().ok_or(Reject)?;
618
808
    let input = input.advance(idx).parse("'")?;
619
158
    Ok(literal_suffix(input))
620
9.81M
}
621
622
macro_rules! next_ch {
623
    ($chars:ident @ $pat:pat) => {
624
        match $chars.next() {
625
            Some((_, ch)) => match ch {
626
                $pat => ch,
627
                _ => return Err(Reject),
628
            },
629
            None => return Err(Reject),
630
        }
631
    };
632
}
633
634
136
fn backslash_x_char<I>(chars: &mut I) -> Result<(), Reject>
635
136
where
636
136
    I: Iterator<Item = (usize, char)>,
637
{
638
136
    next_ch!(chars @ '0'..='7');
639
136
    next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F');
640
135
    Ok(())
641
136
}
642
643
33
fn backslash_x_byte<I>(chars: &mut I) -> Result<(), Reject>
644
33
where
645
33
    I: Iterator<Item = (usize, u8)>,
646
{
647
33
    next_ch!(chars @ b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F');
648
32
    next_ch!(chars @ b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F');
649
22
    Ok(())
650
33
}
651
652
0
fn backslash_x_nonzero<I>(chars: &mut I) -> Result<(), Reject>
653
0
where
654
0
    I: Iterator<Item = (usize, char)>,
655
{
656
0
    let first = next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F');
657
0
    let second = next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F');
658
0
    if first == '0' && second == '0' {
659
0
        Err(Reject)
660
    } else {
661
0
        Ok(())
662
    }
663
0
}
664
665
2
fn backslash_u<I>(chars: &mut I) -> Result<char, Reject>
666
2
where
667
2
    I: Iterator<Item = (usize, char)>,
668
{
669
2
    next_ch!(chars @ '{');
670
0
    let mut value = 0;
671
0
    let mut len = 0;
672
0
    for (_, ch) in chars {
673
0
        let digit = match ch {
674
0
            '0'..='9' => ch as u8 - b'0',
675
0
            'a'..='f' => 10 + ch as u8 - b'a',
676
0
            'A'..='F' => 10 + ch as u8 - b'A',
677
0
            '_' if len > 0 => continue,
678
0
            '}' if len > 0 => return char::from_u32(value).ok_or(Reject),
679
0
            _ => break,
680
        };
681
0
        if len == 6 {
682
0
            break;
683
0
        }
684
0
        value *= 0x10;
685
0
        value += u32::from(digit);
686
0
        len += 1;
687
    }
688
0
    Err(Reject)
689
2
}
690
691
40
fn trailing_backslash(input: &mut Cursor, mut last: u8) -> Result<(), Reject> {
692
40
    let mut whitespace = input.bytes().enumerate();
693
    loop {
694
5.11M
        if last == b'\r' && whitespace.next().map_or(true, |(_, b)| b != b'\n') {
695
3
            return Err(Reject);
696
5.11M
        }
697
5.11M
        match whitespace.next() {
698
5.11M
            Some((_, b @ (b' ' | b'\t' | b'\n' | b'\r'))) => {
699
5.11M
                last = b;
700
5.11M
            }
701
36
            Some((offset, _)) => {
702
36
                *input = input.advance(offset);
703
36
                return Ok(());
704
            }
705
1
            None => return Err(Reject),
706
        }
707
    }
708
40
}
709
710
9.81M
fn float(input: Cursor) -> Result<Cursor, Reject> {
711
9.81M
    let mut rest = float_digits(input)?;
712
919k
    if let Some(ch) = rest.chars().next() {
713
919k
        if is_ident_start(ch) {
714
2.25k
            rest = ident_not_raw(rest)?.0;
715
917k
        }
716
17
    }
717
919k
    word_break(rest)
718
9.81M
}
719
720
9.81M
fn float_digits(input: Cursor) -> Result<Cursor, Reject> {
721
9.81M
    let mut chars = input.chars().peekable();
722
9.81M
    match chars.next() {
723
9.81M
        Some(ch) if '0' <= ch && ch <= '9' => {}
724
7.61M
        _ => return Err(Reject),
725
    }
726
727
2.19M
    let mut len = 1;
728
2.19M
    let mut has_dot = false;
729
2.19M
    let mut has_exp = false;
730
23.5M
    while let Some(&ch) = chars.peek() {
731
23.5M
        match ch {
732
20.6M
            '0'..='9' | '_' => {
733
20.3M
                chars.next();
734
20.3M
                len += 1;
735
20.3M
            }
736
            '.' => {
737
1.69M
                if has_dot {
738
768k
                    break;
739
923k
                }
740
923k
                chars.next();
741
923k
                if chars
742
923k
                    .peek()
743
923k
                    .map_or(false, |&ch| ch == '.' || is_ident_start(ch))
744
                {
745
4.12k
                    return Err(Reject);
746
919k
                }
747
919k
                len += 1;
748
919k
                has_dot = true;
749
            }
750
            'e' | 'E' => {
751
567
                chars.next();
752
567
                len += 1;
753
567
                has_exp = true;
754
567
                break;
755
            }
756
1.42M
            _ => break,
757
        }
758
    }
759
760
2.19M
    if !(has_dot || has_exp) {
761
1.27M
        return Err(Reject);
762
920k
    }
763
764
920k
    if has_exp {
765
567
        let token_before_exp = if has_dot {
766
22
            Ok(input.advance(len - 1))
767
        } else {
768
545
            Err(Reject)
769
        };
770
567
        let mut has_sign = false;
771
567
        let mut has_exp_value = false;
772
1.80M
        while let Some(&ch) = chars.peek() {
773
1.80M
            match ch {
774
                '+' | '-' => {
775
33
                    if has_exp_value {
776
11
                        break;
777
22
                    }
778
22
                    if has_sign {
779
0
                        return token_before_exp;
780
22
                    }
781
22
                    chars.next();
782
22
                    len += 1;
783
22
                    has_sign = true;
784
                }
785
1.13M
                '0'..='9' => {
786
1.13M
                    chars.next();
787
1.13M
                    len += 1;
788
1.13M
                    has_exp_value = true;
789
1.13M
                }
790
667k
                '_' => {
791
667k
                    chars.next();
792
667k
                    len += 1;
793
667k
                }
794
547
                _ => break,
795
            }
796
        }
797
567
        if !has_exp_value {
798
478
            return token_before_exp;
799
89
        }
800
919k
    }
801
802
919k
    Ok(input.advance(len))
803
9.81M
}
804
805
8.89M
fn int(input: Cursor) -> Result<Cursor, Reject> {
806
8.89M
    let mut rest = digits(input)?;
807
1.27M
    if let Some(ch) = rest.chars().next() {
808
1.27M
        if is_ident_start(ch) {
809
2.35k
            rest = ident_not_raw(rest)?.0;
810
1.27M
        }
811
29
    }
812
1.27M
    word_break(rest)
813
8.89M
}
814
815
8.89M
fn digits(mut input: Cursor) -> Result<Cursor, Reject> {
816
8.89M
    let base = if input.starts_with("0x") {
817
85
        input = input.advance(2);
818
85
        16
819
8.89M
    } else if input.starts_with("0o") {
820
14
        input = input.advance(2);
821
14
        8
822
8.89M
    } else if input.starts_with("0b") {
823
56
        input = input.advance(2);
824
56
        2
825
    } else {
826
8.89M
        10
827
    };
828
829
8.89M
    let mut len = 0;
830
8.89M
    let mut empty = true;
831
25.7M
    for b in input.bytes() {
832
25.7M
        match b {
833
19.3M
            b'0'..=b'9' => {
834
12.0M
                let digit = (b - b'0') as u64;
835
12.0M
                if digit >= base {
836
0
                    return Err(Reject);
837
12.0M
                }
838
            }
839
1.29M
            b'a'..=b'f' => {
840
1.11M
                let digit = 10 + (b - b'a') as u64;
841
1.11M
                if digit >= base {
842
91.9k
                    break;
843
1.02M
                }
844
            }
845
4.25M
            b'A'..=b'F' => {
846
303k
                let digit = 10 + (b - b'A') as u64;
847
303k
                if digit >= base {
848
303k
                    break;
849
63
                }
850
            }
851
            b'_' => {
852
3.75M
                if empty && base == 10 {
853
359
                    return Err(Reject);
854
3.75M
                }
855
3.75M
                len += 1;
856
3.75M
                continue;
857
            }
858
8.50M
            _ => break,
859
        }
860
13.0M
        len += 1;
861
13.0M
        empty = false;
862
    }
863
8.89M
    if empty {
864
7.61M
        Err(Reject)
865
    } else {
866
1.27M
        Ok(input.advance(len))
867
    }
868
8.89M
}
869
870
7.61M
fn punct(input: Cursor) -> PResult<Punct> {
871
7.61M
    let (rest, ch) = punct_char(input)?;
872
7.02M
    if ch == '\'' {
873
651
        let (after_lifetime, _ident) = ident_any(rest)?;
874
645
        if after_lifetime.starts_with_char('\'')
875
645
            || (after_lifetime.starts_with_char('#') && !rest.starts_with("r#"))
876
        {
877
6
            Err(Reject)
878
        } else {
879
639
            Ok((rest, Punct::new('\'', Spacing::Joint)))
880
        }
881
    } else {
882
7.02M
        let kind = match punct_char(rest) {
883
4.32M
            Ok(_) => Spacing::Joint,
884
2.69M
            Err(Reject) => Spacing::Alone,
885
        };
886
7.02M
        Ok((rest, Punct::new(ch, kind)))
887
    }
888
7.61M
}
889
890
14.6M
fn punct_char(input: Cursor) -> PResult<char> {
891
14.6M
    if input.starts_with("//") || input.starts_with("/*") {
892
        // Do not accept `/` of a comment as a punct.
893
320
        return Err(Reject);
894
14.6M
    }
895
896
14.6M
    let mut chars = input.chars();
897
14.6M
    let Some(first) = chars.next() else {
898
14
        return Err(Reject);
899
    };
900
14.6M
    let recognized = "~!@#$%^&*-=+|;:,<.>/?'";
901
14.6M
    if recognized.contains(first) {
902
11.3M
        Ok((input.advance(first.len_utf8()), first))
903
    } else {
904
3.28M
        Err(Reject)
905
    }
906
14.6M
}
907
908
18.9M
fn doc_comment<'a>(input: Cursor<'a>, tokens: &mut TokenStreamBuilder) -> PResult<'a, ()> {
909
    #[cfg(span_locations)]
910
    let lo = input.off;
911
18.9M
    let (rest, (comment, inner)) = doc_comment_contents(input)?;
912
14.9k
    let fallback_span = Span {
913
14.9k
        #[cfg(span_locations)]
914
14.9k
        lo,
915
14.9k
        #[cfg(span_locations)]
916
14.9k
        hi: rest.off,
917
14.9k
    };
918
14.9k
    let span = crate::Span::_new_fallback(fallback_span);
919
920
14.9k
    let mut scan_for_bare_cr = comment;
921
15.0k
    while let Some(cr) = scan_for_bare_cr.find('\r') {
922
92
        let rest = &scan_for_bare_cr[cr + 1..];
923
92
        if !rest.starts_with('\n') {
924
28
            return Err(Reject);
925
64
        }
926
64
        scan_for_bare_cr = rest;
927
    }
928
929
14.9k
    let mut pound = Punct::new('#', Spacing::Alone);
930
14.9k
    pound.set_span(span);
931
14.9k
    tokens.push_token_from_parser(TokenTree::Punct(pound));
932
933
14.9k
    if inner {
934
14.3k
        let mut bang = Punct::new('!', Spacing::Alone);
935
14.3k
        bang.set_span(span);
936
14.3k
        tokens.push_token_from_parser(TokenTree::Punct(bang));
937
14.3k
    }
938
939
14.9k
    let doc_ident = crate::Ident::_new_fallback(Ident::new_unchecked("doc", fallback_span));
940
14.9k
    let mut equal = Punct::new('=', Spacing::Alone);
941
14.9k
    equal.set_span(span);
942
14.9k
    let mut literal = crate::Literal::_new_fallback(Literal::string(comment));
943
14.9k
    literal.set_span(span);
944
14.9k
    let mut bracketed = TokenStreamBuilder::with_capacity(3);
945
14.9k
    bracketed.push_token_from_parser(TokenTree::Ident(doc_ident));
946
14.9k
    bracketed.push_token_from_parser(TokenTree::Punct(equal));
947
14.9k
    bracketed.push_token_from_parser(TokenTree::Literal(literal));
948
14.9k
    let group = Group::new(Delimiter::Bracket, bracketed.build());
949
14.9k
    let mut group = crate::Group::_new_fallback(group);
950
14.9k
    group.set_span(span);
951
14.9k
    tokens.push_token_from_parser(TokenTree::Group(group));
952
953
14.9k
    Ok((rest, ()))
954
18.9M
}
955
956
18.9M
fn doc_comment_contents(input: Cursor) -> PResult<(&str, bool)> {
957
18.9M
    if input.starts_with("//!") {
958
14.3k
        let input = input.advance(3);
959
14.3k
        let (input, s) = take_until_newline_or_eof(input);
960
14.3k
        Ok((input, (s, true)))
961
18.9M
    } else if input.starts_with("/*!") {
962
10
        let (input, s) = block_comment(input)?;
963
4
        Ok((input, (&s[3..s.len() - 2], true)))
964
18.9M
    } else if input.starts_with("///") {
965
616
        let input = input.advance(3);
966
616
        if input.starts_with_char('/') {
967
0
            return Err(Reject);
968
616
        }
969
616
        let (input, s) = take_until_newline_or_eof(input);
970
616
        Ok((input, (s, false)))
971
18.9M
    } else if input.starts_with("/**") && !input.rest[3..].starts_with('*') {
972
77
        let (input, s) = block_comment(input)?;
973
68
        Ok((input, (&s[3..s.len() - 2], false)))
974
    } else {
975
18.9M
        Err(Reject)
976
    }
977
18.9M
}
978
979
16.0k
fn take_until_newline_or_eof(input: Cursor) -> (Cursor, &str) {
980
16.0k
    let chars = input.char_indices();
981
982
29.9M
    for (i, ch) in chars {
983
29.9M
        if ch == '\n' {
984
15.9k
            return (input.advance(i), &input.rest[..i]);
985
29.9M
        } else if ch == '\r' && input.rest[i + 1..].starts_with('\n') {
986
120
            return (input.advance(i + 1), &input.rest[..i]);
987
29.9M
        }
988
    }
989
990
57
    (input.advance(input.len()), input.rest)
991
16.0k
}