1#![deny(unstable_features)]
26#[cfg(test)]
29mod tests;
30
31use std::str::Chars;
32
33use LiteralKind::*;
34use TokenKind::*;
35pub use unicode_ident::UNICODE_VERSION;
36use unicode_properties::UnicodeEmoji;
37
38const _: () = {
40 let properties = unicode_properties::UNICODE_VERSION;
41 let ident = unicode_ident::UNICODE_VERSION;
42
43 if properties.0 != ident.0 as u64
44 || properties.1 != ident.1 as u64
45 || properties.2 != ident.2 as u64
46 {
47 {
::core::panicking::panic_fmt(format_args!("unicode-properties and unicode-ident must use the same Unicode version, `unicode_properties::UNICODE_VERSION` and `unicode_ident::UNICODE_VERSION` are different."));
};panic!(
48 "unicode-properties and unicode-ident must use the same Unicode version, \
49 `unicode_properties::UNICODE_VERSION` and `unicode_ident::UNICODE_VERSION` are \
50 different."
51 );
52 }
53};
54
55#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Token {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "Token", "kind",
&self.kind, "len", &&self.len)
}
}Debug)]
59pub struct Token {
60 pub kind: TokenKind,
61 pub len: u32,
62}
63
64impl Token {
65 fn new(kind: TokenKind, len: u32) -> Token {
66 Token { kind, len }
67 }
68}
69
70#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for TokenKind { }
#[automatically_derived]
impl ::core::clone::Clone for TokenKind {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<Option<DocStyle>>;
let _: ::core::clone::AssertParamIsClone<Option<DocStyle>>;
let _: ::core::clone::AssertParamIsClone<bool>;
let _: ::core::clone::AssertParamIsClone<LiteralKind>;
let _: ::core::clone::AssertParamIsClone<u32>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for TokenKind { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for TokenKind {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::LineComment { doc_style: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"LineComment", "doc_style", &__self_0),
Self::BlockComment { doc_style: __self_0, terminated: __self_1 }
=>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"BlockComment", "doc_style", __self_0, "terminated",
&__self_1),
Self::Whitespace =>
::core::fmt::Formatter::write_str(f, "Whitespace"),
Self::Frontmatter {
has_invalid_preceding_whitespace: __self_0,
invalid_infostring: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"Frontmatter", "has_invalid_preceding_whitespace", __self_0,
"invalid_infostring", &__self_1),
Self::Ident => ::core::fmt::Formatter::write_str(f, "Ident"),
Self::InvalidIdent =>
::core::fmt::Formatter::write_str(f, "InvalidIdent"),
Self::RawIdent =>
::core::fmt::Formatter::write_str(f, "RawIdent"),
Self::ForcedKeywordIdent =>
::core::fmt::Formatter::write_str(f, "ForcedKeywordIdent"),
Self::UnknownPrefix =>
::core::fmt::Formatter::write_str(f, "UnknownPrefix"),
Self::UnknownPrefixLifetime =>
::core::fmt::Formatter::write_str(f, "UnknownPrefixLifetime"),
Self::RawLifetime =>
::core::fmt::Formatter::write_str(f, "RawLifetime"),
Self::GuardedStrPrefix =>
::core::fmt::Formatter::write_str(f, "GuardedStrPrefix"),
Self::Literal { kind: __self_0, suffix_start: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"Literal", "kind", __self_0, "suffix_start", &__self_1),
Self::Lifetime { starts_with_number: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"Lifetime", "starts_with_number", &__self_0),
Self::Semi => ::core::fmt::Formatter::write_str(f, "Semi"),
Self::Comma => ::core::fmt::Formatter::write_str(f, "Comma"),
Self::Dot => ::core::fmt::Formatter::write_str(f, "Dot"),
Self::OpenParen =>
::core::fmt::Formatter::write_str(f, "OpenParen"),
Self::CloseParen =>
::core::fmt::Formatter::write_str(f, "CloseParen"),
Self::OpenBrace =>
::core::fmt::Formatter::write_str(f, "OpenBrace"),
Self::CloseBrace =>
::core::fmt::Formatter::write_str(f, "CloseBrace"),
Self::OpenBracket =>
::core::fmt::Formatter::write_str(f, "OpenBracket"),
Self::CloseBracket =>
::core::fmt::Formatter::write_str(f, "CloseBracket"),
Self::At => ::core::fmt::Formatter::write_str(f, "At"),
Self::Pound => ::core::fmt::Formatter::write_str(f, "Pound"),
Self::Tilde => ::core::fmt::Formatter::write_str(f, "Tilde"),
Self::Question =>
::core::fmt::Formatter::write_str(f, "Question"),
Self::Colon => ::core::fmt::Formatter::write_str(f, "Colon"),
Self::Dollar => ::core::fmt::Formatter::write_str(f, "Dollar"),
Self::Eq => ::core::fmt::Formatter::write_str(f, "Eq"),
Self::Bang => ::core::fmt::Formatter::write_str(f, "Bang"),
Self::Lt => ::core::fmt::Formatter::write_str(f, "Lt"),
Self::Gt => ::core::fmt::Formatter::write_str(f, "Gt"),
Self::Minus => ::core::fmt::Formatter::write_str(f, "Minus"),
Self::And => ::core::fmt::Formatter::write_str(f, "And"),
Self::Or => ::core::fmt::Formatter::write_str(f, "Or"),
Self::Plus => ::core::fmt::Formatter::write_str(f, "Plus"),
Self::Star => ::core::fmt::Formatter::write_str(f, "Star"),
Self::Slash => ::core::fmt::Formatter::write_str(f, "Slash"),
Self::Caret => ::core::fmt::Formatter::write_str(f, "Caret"),
Self::Percent => ::core::fmt::Formatter::write_str(f, "Percent"),
Self::Unknown => ::core::fmt::Formatter::write_str(f, "Unknown"),
Self::Eof => ::core::fmt::Formatter::write_str(f, "Eof"),
}
}
}Debug, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for TokenKind { }
#[automatically_derived]
impl ::core::cmp::PartialEq for TokenKind {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other) &&
match (self, other) {
(Self::LineComment { doc_style: __self_0 },
Self::LineComment { doc_style: __arg1_0 }) =>
__self_0 == __arg1_0,
(Self::BlockComment {
doc_style: __self_0, terminated: __self_1 },
Self::BlockComment {
doc_style: __arg1_0, terminated: __arg1_1 }) =>
__self_1 == __arg1_1 && __self_0 == __arg1_0,
(Self::Frontmatter {
has_invalid_preceding_whitespace: __self_0,
invalid_infostring: __self_1 }, Self::Frontmatter {
has_invalid_preceding_whitespace: __arg1_0,
invalid_infostring: __arg1_1 }) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1,
(Self::Literal { kind: __self_0, suffix_start: __self_1 },
Self::Literal { kind: __arg1_0, suffix_start: __arg1_1 }) =>
__self_1 == __arg1_1 && __self_0 == __arg1_0,
(Self::Lifetime { starts_with_number: __self_0 },
Self::Lifetime { starts_with_number: __arg1_0 }) =>
__self_0 == __arg1_0,
_ => true,
}
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for TokenKind {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Option<DocStyle>>;
let _: ::core::cmp::AssertParamIsEq<Option<DocStyle>>;
let _: ::core::cmp::AssertParamIsEq<bool>;
let _: ::core::cmp::AssertParamIsEq<LiteralKind>;
let _: ::core::cmp::AssertParamIsEq<u32>;
}
}Eq)]
72pub enum TokenKind {
73 LineComment {
75 doc_style: Option<DocStyle>,
76 },
77
78 BlockComment {
83 doc_style: Option<DocStyle>,
84 terminated: bool,
85 },
86
87 Whitespace,
89
90 Frontmatter {
91 has_invalid_preceding_whitespace: bool,
92 invalid_infostring: bool,
93 },
94
95 Ident,
97
98 InvalidIdent,
100
101 RawIdent,
103
104 ForcedKeywordIdent,
106
107 UnknownPrefix,
117
118 UnknownPrefixLifetime,
123
124 RawLifetime,
127
128 GuardedStrPrefix,
133
134 Literal {
140 kind: LiteralKind,
141 suffix_start: u32,
142 },
143
144 Lifetime {
146 starts_with_number: bool,
147 },
148
149 Semi,
151 Comma,
153 Dot,
155 OpenParen,
157 CloseParen,
159 OpenBrace,
161 CloseBrace,
163 OpenBracket,
165 CloseBracket,
167 At,
169 Pound,
171 Tilde,
173 Question,
175 Colon,
177 Dollar,
179 Eq,
181 Bang,
183 Lt,
185 Gt,
187 Minus,
189 And,
191 Or,
193 Plus,
195 Star,
197 Slash,
199 Caret,
201 Percent,
203
204 Unknown,
206
207 Eof,
209}
210
211#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for DocStyle { }
#[automatically_derived]
impl ::core::clone::Clone for DocStyle {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for DocStyle { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for DocStyle {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
DocStyle::Outer => "Outer",
DocStyle::Inner => "Inner",
})
}
}Debug, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for DocStyle { }
#[automatically_derived]
impl ::core::cmp::PartialEq for DocStyle {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for DocStyle { }Eq)]
212pub enum DocStyle {
213 Outer,
214 Inner,
215}
216
217#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for LiteralKind { }
#[automatically_derived]
impl ::core::clone::Clone for LiteralKind {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<Base>;
let _: ::core::clone::AssertParamIsClone<bool>;
let _: ::core::clone::AssertParamIsClone<Option<u8>>;
let _: ::core::clone::AssertParamIsClone<Option<u8>>;
let _: ::core::clone::AssertParamIsClone<Option<u8>>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for LiteralKind { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for LiteralKind {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::Int { base: __self_0, empty_int: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f, "Int",
"base", __self_0, "empty_int", &__self_1),
Self::Float { base: __self_0, empty_exponent: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f, "Float",
"base", __self_0, "empty_exponent", &__self_1),
Self::Char { terminated: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "Char",
"terminated", &__self_0),
Self::Byte { terminated: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "Byte",
"terminated", &__self_0),
Self::Str { terminated: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "Str",
"terminated", &__self_0),
Self::ByteStr { terminated: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"ByteStr", "terminated", &__self_0),
Self::CStr { terminated: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "CStr",
"terminated", &__self_0),
Self::RawStr { n_hashes: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"RawStr", "n_hashes", &__self_0),
Self::RawByteStr { n_hashes: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"RawByteStr", "n_hashes", &__self_0),
Self::RawCStr { n_hashes: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"RawCStr", "n_hashes", &__self_0),
}
}
}Debug, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for LiteralKind { }
#[automatically_derived]
impl ::core::cmp::PartialEq for LiteralKind {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other) &&
match (self, other) {
(Self::Int { base: __self_0, empty_int: __self_1 },
Self::Int { base: __arg1_0, empty_int: __arg1_1 }) =>
__self_1 == __arg1_1 && __self_0 == __arg1_0,
(Self::Float { base: __self_0, empty_exponent: __self_1 },
Self::Float { base: __arg1_0, empty_exponent: __arg1_1 }) =>
__self_1 == __arg1_1 && __self_0 == __arg1_0,
(Self::Char { terminated: __self_0 }, Self::Char {
terminated: __arg1_0 }) => __self_0 == __arg1_0,
(Self::Byte { terminated: __self_0 }, Self::Byte {
terminated: __arg1_0 }) => __self_0 == __arg1_0,
(Self::Str { terminated: __self_0 }, Self::Str {
terminated: __arg1_0 }) => __self_0 == __arg1_0,
(Self::ByteStr { terminated: __self_0 }, Self::ByteStr {
terminated: __arg1_0 }) => __self_0 == __arg1_0,
(Self::CStr { terminated: __self_0 }, Self::CStr {
terminated: __arg1_0 }) => __self_0 == __arg1_0,
(Self::RawStr { n_hashes: __self_0 }, Self::RawStr {
n_hashes: __arg1_0 }) => __self_0 == __arg1_0,
(Self::RawByteStr { n_hashes: __self_0 }, Self::RawByteStr {
n_hashes: __arg1_0 }) => __self_0 == __arg1_0,
(Self::RawCStr { n_hashes: __self_0 }, Self::RawCStr {
n_hashes: __arg1_0 }) => __self_0 == __arg1_0,
_ => unsafe { ::core::intrinsics::unreachable() }
}
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for LiteralKind {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Base>;
let _: ::core::cmp::AssertParamIsEq<bool>;
let _: ::core::cmp::AssertParamIsEq<Option<u8>>;
let _: ::core::cmp::AssertParamIsEq<Option<u8>>;
let _: ::core::cmp::AssertParamIsEq<Option<u8>>;
}
}Eq, #[automatically_derived]
impl ::core::cmp::PartialOrd for LiteralKind {
#[inline]
fn partial_cmp(&self, other: &Self)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
}
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for LiteralKind {
#[inline]
fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
match (self, other) {
(Self::Int { base: __self_0, empty_int: __self_1 }, Self::Int {
base: __arg1_0, empty_int: __arg1_1 }) =>
match ::core::cmp::Ord::cmp(__self_0, __arg1_0) {
::core::cmp::Ordering::Equal =>
::core::cmp::Ord::cmp(__self_1, __arg1_1),
cmp => cmp,
},
(Self::Float { base: __self_0, empty_exponent: __self_1 },
Self::Float { base: __arg1_0, empty_exponent: __arg1_1 }) =>
match ::core::cmp::Ord::cmp(__self_0, __arg1_0) {
::core::cmp::Ordering::Equal =>
::core::cmp::Ord::cmp(__self_1, __arg1_1),
cmp => cmp,
},
(Self::Char { terminated: __self_0 }, Self::Char {
terminated: __arg1_0 }) =>
::core::cmp::Ord::cmp(__self_0, __arg1_0),
(Self::Byte { terminated: __self_0 }, Self::Byte {
terminated: __arg1_0 }) =>
::core::cmp::Ord::cmp(__self_0, __arg1_0),
(Self::Str { terminated: __self_0 }, Self::Str {
terminated: __arg1_0 }) =>
::core::cmp::Ord::cmp(__self_0, __arg1_0),
(Self::ByteStr { terminated: __self_0 }, Self::ByteStr {
terminated: __arg1_0 }) =>
::core::cmp::Ord::cmp(__self_0, __arg1_0),
(Self::CStr { terminated: __self_0 }, Self::CStr {
terminated: __arg1_0 }) =>
::core::cmp::Ord::cmp(__self_0, __arg1_0),
(Self::RawStr { n_hashes: __self_0 }, Self::RawStr {
n_hashes: __arg1_0 }) =>
::core::cmp::Ord::cmp(__self_0, __arg1_0),
(Self::RawByteStr { n_hashes: __self_0 }, Self::RawByteStr {
n_hashes: __arg1_0 }) =>
::core::cmp::Ord::cmp(__self_0, __arg1_0),
(Self::RawCStr { n_hashes: __self_0 }, Self::RawCStr {
n_hashes: __arg1_0 }) =>
::core::cmp::Ord::cmp(__self_0, __arg1_0),
_ =>
::core::cmp::Ord::cmp(&::core::intrinsics::discriminant_value(self),
&::core::intrinsics::discriminant_value(other)),
}
}
}Ord)]
224pub enum LiteralKind {
225 Int { base: Base, empty_int: bool },
227 Float { base: Base, empty_exponent: bool },
229 Char { terminated: bool },
231 Byte { terminated: bool },
233 Str { terminated: bool },
235 ByteStr { terminated: bool },
237 CStr { terminated: bool },
239 RawStr { n_hashes: Option<u8> },
242 RawByteStr { n_hashes: Option<u8> },
245 RawCStr { n_hashes: Option<u8> },
247}
248
249#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for GuardedStr { }
#[automatically_derived]
impl ::core::clone::Clone for GuardedStr {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<u32>;
let _: ::core::clone::AssertParamIsClone<bool>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for GuardedStr { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for GuardedStr {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f, "GuardedStr",
"n_hashes", &self.n_hashes, "terminated", &self.terminated,
"token_len", &&self.token_len)
}
}Debug, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for GuardedStr { }
#[automatically_derived]
impl ::core::cmp::PartialEq for GuardedStr {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.n_hashes == other.n_hashes && self.terminated == other.terminated
&& self.token_len == other.token_len
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for GuardedStr {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<u32>;
let _: ::core::cmp::AssertParamIsEq<bool>;
}
}Eq, #[automatically_derived]
impl ::core::cmp::PartialOrd for GuardedStr {
#[inline]
fn partial_cmp(&self, other: &Self)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
}
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for GuardedStr {
#[inline]
fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
match ::core::cmp::Ord::cmp(&self.n_hashes, &other.n_hashes) {
::core::cmp::Ordering::Equal =>
match ::core::cmp::Ord::cmp(&self.terminated,
&other.terminated) {
::core::cmp::Ordering::Equal =>
::core::cmp::Ord::cmp(&self.token_len, &other.token_len),
cmp => cmp,
},
cmp => cmp,
}
}
}Ord)]
254pub struct GuardedStr {
255 pub n_hashes: u32,
256 pub terminated: bool,
257 pub token_len: u32,
258}
259
260#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for RawStrError { }
#[automatically_derived]
impl ::core::clone::Clone for RawStrError {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<char>;
let _: ::core::clone::AssertParamIsClone<u32>;
let _: ::core::clone::AssertParamIsClone<Option<u32>>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for RawStrError { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for RawStrError {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::InvalidStarter { bad_char: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"InvalidStarter", "bad_char", &__self_0),
Self::NoTerminator {
expected: __self_0,
found: __self_1,
possible_terminator_offset: __self_2 } =>
::core::fmt::Formatter::debug_struct_field3_finish(f,
"NoTerminator", "expected", __self_0, "found", __self_1,
"possible_terminator_offset", &__self_2),
Self::TooManyDelimiters { found: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"TooManyDelimiters", "found", &__self_0),
}
}
}Debug, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for RawStrError { }
#[automatically_derived]
impl ::core::cmp::PartialEq for RawStrError {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other) &&
match (self, other) {
(Self::InvalidStarter { bad_char: __self_0 },
Self::InvalidStarter { bad_char: __arg1_0 }) =>
__self_0 == __arg1_0,
(Self::NoTerminator {
expected: __self_0,
found: __self_1,
possible_terminator_offset: __self_2 }, Self::NoTerminator {
expected: __arg1_0,
found: __arg1_1,
possible_terminator_offset: __arg1_2 }) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1 &&
__self_2 == __arg1_2,
(Self::TooManyDelimiters { found: __self_0 },
Self::TooManyDelimiters { found: __arg1_0 }) =>
__self_0 == __arg1_0,
_ => unsafe { ::core::intrinsics::unreachable() }
}
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for RawStrError {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<char>;
let _: ::core::cmp::AssertParamIsEq<u32>;
let _: ::core::cmp::AssertParamIsEq<Option<u32>>;
}
}Eq, #[automatically_derived]
impl ::core::cmp::PartialOrd for RawStrError {
#[inline]
fn partial_cmp(&self, other: &Self)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
}
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for RawStrError {
#[inline]
fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
match (self, other) {
(Self::InvalidStarter { bad_char: __self_0 },
Self::InvalidStarter { bad_char: __arg1_0 }) =>
::core::cmp::Ord::cmp(__self_0, __arg1_0),
(Self::NoTerminator {
expected: __self_0,
found: __self_1,
possible_terminator_offset: __self_2 }, Self::NoTerminator {
expected: __arg1_0,
found: __arg1_1,
possible_terminator_offset: __arg1_2 }) =>
match ::core::cmp::Ord::cmp(__self_0, __arg1_0) {
::core::cmp::Ordering::Equal =>
match ::core::cmp::Ord::cmp(__self_1, __arg1_1) {
::core::cmp::Ordering::Equal =>
::core::cmp::Ord::cmp(__self_2, __arg1_2),
cmp => cmp,
},
cmp => cmp,
},
(Self::TooManyDelimiters { found: __self_0 },
Self::TooManyDelimiters { found: __arg1_0 }) =>
::core::cmp::Ord::cmp(__self_0, __arg1_0),
_ =>
::core::cmp::Ord::cmp(&::core::intrinsics::discriminant_value(self),
&::core::intrinsics::discriminant_value(other)),
}
}
}Ord)]
261pub enum RawStrError {
262 InvalidStarter { bad_char: char },
264 NoTerminator { expected: u32, found: u32, possible_terminator_offset: Option<u32> },
268 TooManyDelimiters { found: u32 },
270}
271
272#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Base { }
#[automatically_derived]
impl ::core::clone::Clone for Base {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Base { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for Base {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
Base::Binary => "Binary",
Base::Octal => "Octal",
Base::Decimal => "Decimal",
Base::Hexadecimal => "Hexadecimal",
})
}
}Debug, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for Base { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Base {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for Base { }Eq, #[automatically_derived]
impl ::core::cmp::PartialOrd for Base {
#[inline]
fn partial_cmp(&self, other: &Self)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
}
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for Base {
#[inline]
fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
::core::cmp::Ord::cmp(&::core::intrinsics::discriminant_value(self),
&::core::intrinsics::discriminant_value(other))
}
}Ord)]
274pub enum Base {
275 Binary = 2,
277 Octal = 8,
279 Decimal = 10,
281 Hexadecimal = 16,
283}
284
285pub fn strip_shebang(input: &str) -> Option<usize> {
288 if let Some(input_tail) = input.strip_prefix("#!") {
292 let next_non_whitespace_token =
295 tokenize(input_tail, FrontmatterAllowed::No).map(|tok| tok.kind).find(|tok| {
296 !#[allow(non_exhaustive_omitted_patterns)] match tok {
TokenKind::Whitespace | TokenKind::LineComment { doc_style: None } |
TokenKind::BlockComment { doc_style: None, .. } => true,
_ => false,
}matches!(
297 tok,
298 TokenKind::Whitespace
299 | TokenKind::LineComment { doc_style: None }
300 | TokenKind::BlockComment { doc_style: None, .. }
301 )
302 });
303 if next_non_whitespace_token != Some(TokenKind::OpenBracket) {
304 return Some(2 + input_tail.lines().next().unwrap_or_default().len());
306 }
307 }
308 None
309}
310
311#[inline]
314pub fn validate_raw_str(input: &str, prefix_len: u32) -> Result<(), RawStrError> {
315 if true {
if !!input.is_empty() {
::core::panicking::panic("assertion failed: !input.is_empty()")
};
};debug_assert!(!input.is_empty());
316 let mut cursor = Cursor::new(input, FrontmatterAllowed::No);
317 for _ in 0..prefix_len {
319 cursor.bump().unwrap();
320 }
321 cursor.raw_double_quoted_string(prefix_len).map(|_| ())
322}
323
324pub fn tokenize(
331 input: &str,
332 frontmatter_allowed: FrontmatterAllowed,
333) -> impl Iterator<Item = Token> {
334 let mut cursor = Cursor::new(input, frontmatter_allowed);
335 std::iter::from_fn(move || {
336 let token = cursor.advance_token();
337 if token.kind != TokenKind::Eof { Some(token) } else { None }
338 })
339}
340
341pub fn is_whitespace(c: char) -> bool {
345 #[allow(non_exhaustive_omitted_patterns)] match c {
'\u{000A}' | '\u{000B}' | '\u{000C}' | '\u{000D}' | '\u{0085}' |
'\u{2028}' | '\u{2029}' | '\u{200E}' | '\u{200F}' | '\u{0009}' |
'\u{0020}' => true,
_ => false,
}matches!(
351 c,
352 | '\u{000A}' | '\u{000B}' | '\u{000C}' | '\u{000D}' | '\u{0085}' | '\u{2028}' | '\u{2029}' | '\u{200E}' | '\u{200F}' | '\u{0009}' | '\u{0020}' )
369}
370
371pub fn is_horizontal_whitespace(c: char) -> bool {
373 #[allow(non_exhaustive_omitted_patterns)] match c {
'\u{0009}' | '\u{0020}' => true,
_ => false,
}matches!(
380 c,
381 '\u{0009}' | '\u{0020}' )
385}
386
387pub fn is_id_start(c: char) -> bool {
391 c == '_' || unicode_ident::is_xid_start(c)
393}
394
395pub fn is_id_continue(c: char) -> bool {
399 unicode_ident::is_xid_continue(c)
400}
401
402pub fn is_ident(string: &str) -> bool {
404 let mut chars = string.chars();
405 if let Some(start) = chars.next() {
406 is_id_start(start) && chars.all(is_id_continue)
407 } else {
408 false
409 }
410}
411
412pub enum FrontmatterAllowed {
413 Yes,
414 No,
415}
416
417pub struct Cursor<'a> {
422 len_remaining: usize,
423 chars: Chars<'a>,
425 pub(crate) frontmatter_allowed: FrontmatterAllowed,
426 #[cfg(debug_assertions)]
427 prev: char,
428}
429
430const EOF_CHAR: char = '\0';
431
432impl<'a> Cursor<'a> {
433 pub fn new(input: &'a str, frontmatter_allowed: FrontmatterAllowed) -> Cursor<'a> {
434 Cursor {
435 len_remaining: input.len(),
436 chars: input.chars(),
437 frontmatter_allowed,
438 #[cfg(debug_assertions)]
439 prev: EOF_CHAR,
440 }
441 }
442
443 pub fn as_str(&self) -> &'a str {
444 self.chars.as_str()
445 }
446
447 pub(crate) fn prev(&self) -> char {
450 #[cfg(debug_assertions)]
451 {
452 self.prev
453 }
454
455 #[cfg(not(debug_assertions))]
456 {
457 EOF_CHAR
458 }
459 }
460
461 pub fn first(&self) -> char {
466 self.chars.clone().next().unwrap_or(EOF_CHAR)
468 }
469
470 pub(crate) fn second(&self) -> char {
472 let mut iter = self.chars.clone();
474 iter.next();
475 iter.next().unwrap_or(EOF_CHAR)
476 }
477
478 pub fn third(&self) -> char {
480 let mut iter = self.chars.clone();
482 iter.next();
483 iter.next();
484 iter.next().unwrap_or(EOF_CHAR)
485 }
486
487 pub(crate) fn is_eof(&self) -> bool {
489 self.chars.as_str().is_empty()
490 }
491
492 pub(crate) fn pos_within_token(&self) -> u32 {
494 (self.len_remaining - self.chars.as_str().len()) as u32
495 }
496
497 pub(crate) fn reset_pos_within_token(&mut self) {
499 self.len_remaining = self.chars.as_str().len();
500 }
501
502 pub(crate) fn bump(&mut self) -> Option<char> {
504 let c = self.chars.next()?;
505
506 #[cfg(debug_assertions)]
507 {
508 self.prev = c;
509 }
510
511 Some(c)
512 }
513
514 pub(crate) fn bump_bytes(&mut self, n: usize) {
516 self.chars = self.as_str()[n..].chars();
517 }
518
519 pub(crate) fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) {
521 while predicate(self.first()) && !self.is_eof() {
524 self.bump();
525 }
526 }
527
528 pub(crate) fn eat_until(&mut self, byte: u8) {
529 self.chars = match memchr::memchr(byte, self.as_str().as_bytes()) {
530 Some(index) => self.as_str()[index..].chars(),
531 None => "".chars(),
532 }
533 }
534
535 pub fn advance_token(&mut self) -> Token {
537 let Some(first_char) = self.bump() else {
538 return Token::new(TokenKind::Eof, 0);
539 };
540
541 let token_kind = match first_char {
542 c if #[allow(non_exhaustive_omitted_patterns)] match self.frontmatter_allowed {
FrontmatterAllowed::Yes => true,
_ => false,
}matches!(self.frontmatter_allowed, FrontmatterAllowed::Yes)
543 && is_whitespace(c) =>
544 {
545 let mut last = first_char;
546 while is_whitespace(self.first()) {
547 let Some(c) = self.bump() else {
548 break;
549 };
550 last = c;
551 }
552 if last != '\n' && self.as_str().starts_with("---") {
556 self.bump();
557 self.frontmatter(true)
558 } else {
559 Whitespace
560 }
561 }
562 '-' if #[allow(non_exhaustive_omitted_patterns)] match self.frontmatter_allowed {
FrontmatterAllowed::Yes => true,
_ => false,
}matches!(self.frontmatter_allowed, FrontmatterAllowed::Yes)
563 && self.as_str().starts_with("--") =>
564 {
565 self.frontmatter(false)
567 }
568 '/' => match self.first() {
570 '/' => self.line_comment(),
571 '*' => self.block_comment(),
572 _ => Slash,
573 },
574
575 c if is_whitespace(c) => self.whitespace(),
577
578 'r' => match (self.first(), self.second()) {
580 ('#', c1) if is_id_start(c1) => {
581 self.bump(); self.eat_identifier();
583 RawIdent
584 }
585 ('#', _) | ('"', _) => {
586 let res = self.raw_double_quoted_string(1);
587 let suffix_start = self.pos_within_token();
588 if res.is_ok() {
589 self.eat_literal_suffix();
590 }
591 let kind = RawStr { n_hashes: res.ok() };
592 Literal { kind, suffix_start }
593 }
594 _ => self.ident_or_unknown_prefix(),
595 },
596
597 'k' => match (self.first(), self.second()) {
599 ('#', c1) if is_id_start(c1) => {
600 self.bump(); self.eat_identifier();
602 ForcedKeywordIdent
603 }
604 _ => self.ident_or_unknown_prefix(),
605 },
606
607 'b' => self.c_or_byte_string(
609 |terminated| ByteStr { terminated },
610 |n_hashes| RawByteStr { n_hashes },
611 Some(|terminated| Byte { terminated }),
612 ),
613
614 'c' => self.c_or_byte_string(
616 |terminated| CStr { terminated },
617 |n_hashes| RawCStr { n_hashes },
618 None,
619 ),
620
621 c if is_id_start(c) => self.ident_or_unknown_prefix(),
624
625 c @ '0'..='9' => {
627 let literal_kind = self.number(c);
628 let suffix_start = self.pos_within_token();
629 self.eat_literal_suffix();
630 TokenKind::Literal { kind: literal_kind, suffix_start }
631 }
632
633 '#' if #[allow(non_exhaustive_omitted_patterns)] match self.first() {
'"' | '#' => true,
_ => false,
}matches!(self.first(), '"' | '#') => {
635 self.bump();
636 TokenKind::GuardedStrPrefix
637 }
638
639 ';' => Semi,
641 ',' => Comma,
642 '.' => Dot,
643 '(' => OpenParen,
644 ')' => CloseParen,
645 '{' => OpenBrace,
646 '}' => CloseBrace,
647 '[' => OpenBracket,
648 ']' => CloseBracket,
649 '@' => At,
650 '#' => Pound,
651 '~' => Tilde,
652 '?' => Question,
653 ':' => Colon,
654 '$' => Dollar,
655 '=' => Eq,
656 '!' => Bang,
657 '<' => Lt,
658 '>' => Gt,
659 '-' => Minus,
660 '&' => And,
661 '|' => Or,
662 '+' => Plus,
663 '*' => Star,
664 '^' => Caret,
665 '%' => Percent,
666
667 '\'' => self.lifetime_or_char(),
669
670 '"' => {
672 let terminated = self.double_quoted_string();
673 let suffix_start = self.pos_within_token();
674 if terminated {
675 self.eat_literal_suffix();
676 }
677 let kind = Str { terminated };
678 Literal { kind, suffix_start }
679 }
680 c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident(),
682 _ => Unknown,
683 };
684 if #[allow(non_exhaustive_omitted_patterns)] match self.frontmatter_allowed {
FrontmatterAllowed::Yes => true,
_ => false,
}matches!(self.frontmatter_allowed, FrontmatterAllowed::Yes)
685 && !#[allow(non_exhaustive_omitted_patterns)] match token_kind {
Whitespace => true,
_ => false,
}matches!(token_kind, Whitespace)
686 {
687 self.frontmatter_allowed = FrontmatterAllowed::No;
689 }
690 let res = Token::new(token_kind, self.pos_within_token());
691 self.reset_pos_within_token();
692 res
693 }
694
695 fn frontmatter(&mut self, has_invalid_preceding_whitespace: bool) -> TokenKind {
697 if true {
{
match (&'-', &self.prev()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};
};debug_assert_eq!('-', self.prev());
698
699 let pos = self.pos_within_token();
700 self.eat_while(|c| c == '-');
701
702 let length_opening = self.pos_within_token() - pos + 1;
704
705 if true {
if !(length_opening >= 3) {
::core::panicking::panic("assertion failed: length_opening >= 3")
};
};debug_assert!(length_opening >= 3);
707
708 self.eat_while(|ch| ch != '\n' && is_horizontal_whitespace(ch));
710
711 if is_id_start(self.first()) {
714 self.bump();
715 self.eat_while(|c| is_id_continue(c) || c == '-' || c == '.');
716 }
717
718 self.eat_while(|ch| ch != '\n' && is_horizontal_whitespace(ch));
719 let invalid_infostring = self.first() != '\n';
720
721 let mut found = false;
722 let nl_fence_pattern = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\n{0:-<1$}", "",
length_opening as usize))
})format!("\n{:-<1$}", "", length_opening as usize);
723 if let Some(closing) = self.as_str().find(&nl_fence_pattern) {
724 self.bump_bytes(closing + nl_fence_pattern.len());
726 self.eat_until(b'\n');
734 found = true;
735 }
736
737 if !found {
738 let mut rest = self.as_str();
742 let mut potential_closing = rest
745 .find("\n---")
746 .map(|x| x + 1)
750 .or_else(|| rest.find("\nuse "))
751 .or_else(|| rest.find("\n//!"))
752 .or_else(|| rest.find("\n#!["));
753
754 if potential_closing.is_none() {
755 let mut base_index = 0;
758 while let Some(closing) = rest.find("---") {
759 let preceding_chars_start = rest[..closing].rfind("\n").map_or(0, |i| i + 1);
760 if rest[preceding_chars_start..closing].chars().all(is_horizontal_whitespace) {
761 potential_closing = Some(closing + base_index);
763 break;
764 } else {
765 rest = &rest[closing + 3..];
766 base_index += closing + 3;
767 }
768 }
769 }
770
771 if let Some(potential_closing) = potential_closing {
772 self.bump_bytes(potential_closing);
774 self.eat_until(b'\n');
775 } else {
776 self.eat_while(|_| true);
778 }
779 }
780
781 Frontmatter { has_invalid_preceding_whitespace, invalid_infostring }
782 }
783
784 fn line_comment(&mut self) -> TokenKind {
785 if true {
if !(self.prev() == '/' && self.first() == '/') {
::core::panicking::panic("assertion failed: self.prev() == \'/\' && self.first() == \'/\'")
};
};debug_assert!(self.prev() == '/' && self.first() == '/');
786 self.bump();
787
788 let doc_style = match self.first() {
789 '!' => Some(DocStyle::Inner),
791 '/' if self.second() != '/' => Some(DocStyle::Outer),
793 _ => None,
794 };
795
796 self.eat_until(b'\n');
797 LineComment { doc_style }
798 }
799
800 fn block_comment(&mut self) -> TokenKind {
801 if true {
if !(self.prev() == '/' && self.first() == '*') {
::core::panicking::panic("assertion failed: self.prev() == \'/\' && self.first() == \'*\'")
};
};debug_assert!(self.prev() == '/' && self.first() == '*');
802 self.bump();
803
804 let doc_style = match self.first() {
805 '!' => Some(DocStyle::Inner),
807 '*' if !#[allow(non_exhaustive_omitted_patterns)] match self.second() {
'*' | '/' => true,
_ => false,
}matches!(self.second(), '*' | '/') => Some(DocStyle::Outer),
810 _ => None,
811 };
812
813 let mut depth = 1usize;
814 while let Some(c) = self.bump() {
815 match c {
816 '/' if self.first() == '*' => {
817 self.bump();
818 depth += 1;
819 }
820 '*' if self.first() == '/' => {
821 self.bump();
822 depth -= 1;
823 if depth == 0 {
824 break;
828 }
829 }
830 _ => (),
831 }
832 }
833
834 BlockComment { doc_style, terminated: depth == 0 }
835 }
836
837 fn whitespace(&mut self) -> TokenKind {
838 if true {
if !is_whitespace(self.prev()) {
::core::panicking::panic("assertion failed: is_whitespace(self.prev())")
};
};debug_assert!(is_whitespace(self.prev()));
839 self.eat_while(is_whitespace);
840 Whitespace
841 }
842
843 fn ident_or_unknown_prefix(&mut self) -> TokenKind {
844 if true {
if !is_id_start(self.prev()) {
::core::panicking::panic("assertion failed: is_id_start(self.prev())")
};
};debug_assert!(is_id_start(self.prev()));
845 self.eat_while(is_id_continue);
847 match self.first() {
850 '#' | '"' | '\'' => UnknownPrefix,
851 c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident(),
852 _ => Ident,
853 }
854 }
855
856 fn invalid_ident(&mut self) -> TokenKind {
857 self.eat_while(|c| {
859 const ZERO_WIDTH_JOINER: char = '\u{200d}';
860 is_id_continue(c) || (!c.is_ascii() && c.is_emoji_char()) || c == ZERO_WIDTH_JOINER
861 });
862 InvalidIdent
867 }
868
869 fn c_or_byte_string(
870 &mut self,
871 mk_kind: fn(bool) -> LiteralKind,
872 mk_kind_raw: fn(Option<u8>) -> LiteralKind,
873 single_quoted: Option<fn(bool) -> LiteralKind>,
874 ) -> TokenKind {
875 match (self.first(), self.second(), single_quoted) {
876 ('\'', _, Some(single_quoted)) => {
877 self.bump();
878 let terminated = self.single_quoted_string();
879 let suffix_start = self.pos_within_token();
880 if terminated {
881 self.eat_literal_suffix();
882 }
883 let kind = single_quoted(terminated);
884 Literal { kind, suffix_start }
885 }
886 ('"', _, _) => {
887 self.bump();
888 let terminated = self.double_quoted_string();
889 let suffix_start = self.pos_within_token();
890 if terminated {
891 self.eat_literal_suffix();
892 }
893 let kind = mk_kind(terminated);
894 Literal { kind, suffix_start }
895 }
896 ('r', '"', _) | ('r', '#', _) => {
897 self.bump();
898 let res = self.raw_double_quoted_string(2);
899 let suffix_start = self.pos_within_token();
900 if res.is_ok() {
901 self.eat_literal_suffix();
902 }
903 let kind = mk_kind_raw(res.ok());
904 Literal { kind, suffix_start }
905 }
906 _ => self.ident_or_unknown_prefix(),
907 }
908 }
909
910 fn number(&mut self, first_digit: char) -> LiteralKind {
911 if true {
if !('0' <= self.prev() && self.prev() <= '9') {
::core::panicking::panic("assertion failed: \'0\' <= self.prev() && self.prev() <= \'9\'")
};
};debug_assert!('0' <= self.prev() && self.prev() <= '9');
912 let mut base = Base::Decimal;
913 if first_digit == '0' {
914 match self.first() {
916 'b' => {
917 base = Base::Binary;
918 self.bump();
919 if !self.eat_decimal_digits() {
920 return Int { base, empty_int: true };
921 }
922 }
923 'o' => {
924 base = Base::Octal;
925 self.bump();
926 if !self.eat_decimal_digits() {
927 return Int { base, empty_int: true };
928 }
929 }
930 'x' => {
931 base = Base::Hexadecimal;
932 self.bump();
933 if !self.eat_hexadecimal_digits() {
934 return Int { base, empty_int: true };
935 }
936 }
937 '0'..='9' | '_' => {
939 self.eat_decimal_digits();
940 }
941
942 '.' | 'e' | 'E' => {}
944
945 _ => return Int { base, empty_int: false },
947 }
948 } else {
949 self.eat_decimal_digits();
951 }
952
953 match self.first() {
954 '.' if self.second() != '.' && !is_id_start(self.second()) => {
958 self.bump();
961 let mut empty_exponent = false;
962 if self.first().is_ascii_digit() {
963 self.eat_decimal_digits();
964 match self.first() {
965 'e' | 'E' => {
966 self.bump();
967 empty_exponent = !self.eat_float_exponent();
968 }
969 _ => (),
970 }
971 }
972 Float { base, empty_exponent }
973 }
974 'e' | 'E' => {
975 self.bump();
976 let empty_exponent = !self.eat_float_exponent();
977 Float { base, empty_exponent }
978 }
979 _ => Int { base, empty_int: false },
980 }
981 }
982
983 fn lifetime_or_char(&mut self) -> TokenKind {
984 if true {
if !(self.prev() == '\'') {
::core::panicking::panic("assertion failed: self.prev() == \'\\\'\'")
};
};debug_assert!(self.prev() == '\'');
985
986 let can_be_a_lifetime = if self.second() == '\'' {
987 false
989 } else {
990 is_id_start(self.first()) || self.first().is_ascii_digit()
994 };
995
996 if !can_be_a_lifetime {
997 let terminated = self.single_quoted_string();
998 let suffix_start = self.pos_within_token();
999 if terminated {
1000 self.eat_literal_suffix();
1001 }
1002 let kind = Char { terminated };
1003 return Literal { kind, suffix_start };
1004 }
1005
1006 if self.first() == 'r' && self.second() == '#' && is_id_start(self.third()) {
1007 self.bump();
1009 self.bump();
1010 self.bump();
1011 self.eat_while(is_id_continue);
1012 return RawLifetime;
1013 }
1014
1015 let starts_with_number = self.first().is_ascii_digit();
1018
1019 self.bump();
1023 self.eat_while(is_id_continue);
1024
1025 match self.first() {
1026 '\'' => {
1030 self.bump();
1031 let kind = Char { terminated: true };
1032 Literal { kind, suffix_start: self.pos_within_token() }
1033 }
1034 '#' if !starts_with_number => UnknownPrefixLifetime,
1035 _ => Lifetime { starts_with_number },
1036 }
1037 }
1038
1039 fn single_quoted_string(&mut self) -> bool {
1040 if true {
if !(self.prev() == '\'') {
::core::panicking::panic("assertion failed: self.prev() == \'\\\'\'")
};
};debug_assert!(self.prev() == '\'');
1041 if self.second() == '\'' && self.first() != '\\' {
1043 self.bump();
1044 self.bump();
1045 return true;
1046 }
1047
1048 loop {
1052 match self.first() {
1053 '\'' => {
1055 self.bump();
1056 return true;
1057 }
1058 '/' => break,
1061 '\n' if self.second() != '\'' => break,
1063 EOF_CHAR if self.is_eof() => break,
1065 '\\' => {
1067 self.bump();
1068 self.bump();
1069 }
1070 _ => {
1072 self.bump();
1073 }
1074 }
1075 }
1076 false
1078 }
1079
1080 fn double_quoted_string(&mut self) -> bool {
1083 if true {
if !(self.prev() == '"') {
::core::panicking::panic("assertion failed: self.prev() == \'\"\'")
};
};debug_assert!(self.prev() == '"');
1084 while let Some(c) = self.bump() {
1085 match c {
1086 '"' => {
1087 return true;
1088 }
1089 '\\' if self.first() == '\\' || self.first() == '"' => {
1090 self.bump();
1092 }
1093 _ => (),
1094 }
1095 }
1096 false
1098 }
1099
1100 pub fn guarded_double_quoted_string(&mut self) -> Option<GuardedStr> {
1109 if true {
if !(self.prev() != '#') {
::core::panicking::panic("assertion failed: self.prev() != \'#\'")
};
};debug_assert!(self.prev() != '#');
1110
1111 let mut n_start_hashes: u32 = 0;
1112 while self.first() == '#' {
1113 n_start_hashes += 1;
1114 self.bump();
1115 }
1116
1117 if self.first() != '"' {
1118 return None;
1119 }
1120 self.bump();
1121 if true {
if !(self.prev() == '"') {
::core::panicking::panic("assertion failed: self.prev() == \'\"\'")
};
};debug_assert!(self.prev() == '"');
1122
1123 let terminated = self.double_quoted_string();
1126 if !terminated {
1127 let token_len = self.pos_within_token();
1128 self.reset_pos_within_token();
1129
1130 return Some(GuardedStr { n_hashes: n_start_hashes, terminated: false, token_len });
1131 }
1132
1133 let mut n_end_hashes = 0;
1138 while self.first() == '#' && n_end_hashes < n_start_hashes {
1139 n_end_hashes += 1;
1140 self.bump();
1141 }
1142
1143 self.eat_literal_suffix();
1147
1148 let token_len = self.pos_within_token();
1149 self.reset_pos_within_token();
1150
1151 Some(GuardedStr { n_hashes: n_start_hashes, terminated: true, token_len })
1152 }
1153
1154 fn raw_double_quoted_string(&mut self, prefix_len: u32) -> Result<u8, RawStrError> {
1156 let n_hashes = self.raw_string_unvalidated(prefix_len)?;
1159 match u8::try_from(n_hashes) {
1161 Ok(num) => Ok(num),
1162 Err(_) => Err(RawStrError::TooManyDelimiters { found: n_hashes }),
1163 }
1164 }
1165
1166 fn raw_string_unvalidated(&mut self, prefix_len: u32) -> Result<u32, RawStrError> {
1167 if true {
if !(self.prev() == 'r') {
::core::panicking::panic("assertion failed: self.prev() == \'r\'")
};
};debug_assert!(self.prev() == 'r');
1168 let start_pos = self.pos_within_token();
1169 let mut possible_terminator_offset = None;
1170 let mut max_hashes = 0;
1171
1172 let mut eaten = 0;
1174 while self.first() == '#' {
1175 eaten += 1;
1176 self.bump();
1177 }
1178 let n_start_hashes = eaten;
1179
1180 match self.bump() {
1182 Some('"') => (),
1183 c => {
1184 let c = c.unwrap_or(EOF_CHAR);
1185 return Err(RawStrError::InvalidStarter { bad_char: c });
1186 }
1187 }
1188
1189 loop {
1192 self.eat_until(b'"');
1193
1194 if self.is_eof() {
1195 return Err(RawStrError::NoTerminator {
1196 expected: n_start_hashes,
1197 found: max_hashes,
1198 possible_terminator_offset,
1199 });
1200 }
1201
1202 self.bump();
1204
1205 let mut n_end_hashes = 0;
1211 while self.first() == '#' && n_end_hashes < n_start_hashes {
1212 n_end_hashes += 1;
1213 self.bump();
1214 }
1215
1216 if n_end_hashes == n_start_hashes {
1217 return Ok(n_start_hashes);
1218 } else if n_end_hashes > max_hashes {
1219 possible_terminator_offset =
1222 Some(self.pos_within_token() - start_pos - n_end_hashes + prefix_len);
1223 max_hashes = n_end_hashes;
1224 }
1225 }
1226 }
1227
1228 fn eat_decimal_digits(&mut self) -> bool {
1229 let mut has_digits = false;
1230 loop {
1231 match self.first() {
1232 '_' => {
1233 self.bump();
1234 }
1235 '0'..='9' => {
1236 has_digits = true;
1237 self.bump();
1238 }
1239 _ => break,
1240 }
1241 }
1242 has_digits
1243 }
1244
1245 fn eat_hexadecimal_digits(&mut self) -> bool {
1246 let mut has_digits = false;
1247 loop {
1248 match self.first() {
1249 '_' => {
1250 self.bump();
1251 }
1252 '0'..='9' | 'a'..='f' | 'A'..='F' => {
1253 has_digits = true;
1254 self.bump();
1255 }
1256 _ => break,
1257 }
1258 }
1259 has_digits
1260 }
1261
1262 fn eat_float_exponent(&mut self) -> bool {
1265 if true {
if !(self.prev() == 'e' || self.prev() == 'E') {
::core::panicking::panic("assertion failed: self.prev() == \'e\' || self.prev() == \'E\'")
};
};debug_assert!(self.prev() == 'e' || self.prev() == 'E');
1266 if self.first() == '-' || self.first() == '+' {
1267 self.bump();
1268 }
1269 self.eat_decimal_digits()
1270 }
1271
1272 fn eat_literal_suffix(&mut self) {
1274 self.eat_identifier();
1275 }
1276
1277 fn eat_identifier(&mut self) {
1280 if !is_id_start(self.first()) {
1281 return;
1282 }
1283 self.bump();
1284
1285 self.eat_while(is_id_continue);
1286 }
1287}