Coverage Report

Created: 2026-01-17 06:43

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