blob: 3a66cb763f5c12ddae41b90ff055f897bff42f54 [file] [log] [blame]
Alex Crichton9a4dca22018-03-28 06:32:19 -07001use proc_macro2::{Literal, Span};
David Tolnay360efd22018-01-04 23:35:26 -08002use std::str;
3
David Tolnay7d1d1282018-01-06 16:10:51 -08004#[cfg(feature = "printing")]
Alex Crichtona74a1c82018-05-16 10:20:44 -07005use proc_macro2::Ident;
David Tolnay7d1d1282018-01-06 16:10:51 -08006
David Tolnayd53ac2b2018-01-27 19:00:06 -08007#[cfg(feature = "parsing")]
8use proc_macro2::TokenStream;
David Tolnayd53ac2b2018-01-27 19:00:06 -08009
David Tolnay60fafad2018-02-03 09:18:03 -080010use proc_macro2::TokenTree;
11
David Tolnay360efd22018-01-04 23:35:26 -080012#[cfg(feature = "extra-traits")]
Alex Crichtonccbb45d2017-05-23 10:58:24 -070013use std::hash::{Hash, Hasher};
14
David Tolnay4fb71232018-08-25 23:14:50 -040015#[cfg(feature = "parsing")]
16use lookahead;
David Tolnaye82a2b12018-08-30 16:31:10 -070017#[cfg(feature = "parsing")]
David Tolnay29e8d8c2019-03-07 22:43:15 -080018use parse::{Parse, Parser, Result};
David Tolnay4fb71232018-08-25 23:14:50 -040019
David Tolnay360efd22018-01-04 23:35:26 -080020ast_enum_of_structs! {
David Tolnayabf5c2e2018-01-06 23:30:04 -080021 /// A Rust literal such as a string or integer or boolean.
David Tolnay614a0142018-01-07 10:25:43 -080022 ///
David Tolnay461d98e2018-01-07 11:07:19 -080023 /// *This type is available if Syn is built with the `"derive"` or `"full"`
24 /// feature.*
25 ///
David Tolnay614a0142018-01-07 10:25:43 -080026 /// # Syntax tree enum
27 ///
28 /// This type is a [syntax tree enum].
29 ///
30 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
David Tolnay360efd22018-01-04 23:35:26 -080031 pub enum Lit {
David Tolnayabf5c2e2018-01-06 23:30:04 -080032 /// A UTF-8 string literal: `"foo"`.
David Tolnay461d98e2018-01-07 11:07:19 -080033 ///
34 /// *This type is available if Syn is built with the `"derive"` or
35 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080036 pub Str(LitStr #manual_extra_traits {
37 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080038 }),
Alex Crichtonccbb45d2017-05-23 10:58:24 -070039
David Tolnayabf5c2e2018-01-06 23:30:04 -080040 /// A byte string literal: `b"foo"`.
David Tolnay461d98e2018-01-07 11:07:19 -080041 ///
42 /// *This type is available if Syn is built with the `"derive"` or
43 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080044 pub ByteStr(LitByteStr #manual_extra_traits {
45 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080046 }),
47
David Tolnayabf5c2e2018-01-06 23:30:04 -080048 /// A byte literal: `b'f'`.
David Tolnay461d98e2018-01-07 11:07:19 -080049 ///
50 /// *This type is available if Syn is built with the `"derive"` or
51 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080052 pub Byte(LitByte #manual_extra_traits {
53 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080054 }),
55
David Tolnayabf5c2e2018-01-06 23:30:04 -080056 /// A character literal: `'a'`.
David Tolnay461d98e2018-01-07 11:07:19 -080057 ///
58 /// *This type is available if Syn is built with the `"derive"` or
59 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080060 pub Char(LitChar #manual_extra_traits {
61 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080062 }),
63
David Tolnayabf5c2e2018-01-06 23:30:04 -080064 /// An integer literal: `1` or `1u16`.
David Tolnay360efd22018-01-04 23:35:26 -080065 ///
66 /// Holds up to 64 bits of data. Use `LitVerbatim` for any larger
67 /// integer literal.
David Tolnay461d98e2018-01-07 11:07:19 -080068 ///
69 /// *This type is available if Syn is built with the `"derive"` or
70 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080071 pub Int(LitInt #manual_extra_traits {
72 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080073 }),
74
David Tolnayabf5c2e2018-01-06 23:30:04 -080075 /// A floating point literal: `1f64` or `1.0e10f64`.
David Tolnay360efd22018-01-04 23:35:26 -080076 ///
77 /// Must be finite. May not be infinte or NaN.
David Tolnay461d98e2018-01-07 11:07:19 -080078 ///
79 /// *This type is available if Syn is built with the `"derive"` or
80 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080081 pub Float(LitFloat #manual_extra_traits {
82 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080083 }),
84
David Tolnayabf5c2e2018-01-06 23:30:04 -080085 /// A boolean literal: `true` or `false`.
David Tolnay461d98e2018-01-07 11:07:19 -080086 ///
87 /// *This type is available if Syn is built with the `"derive"` or
88 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080089 pub Bool(LitBool #manual_extra_traits {
90 pub value: bool,
91 pub span: Span,
92 }),
93
David Tolnayabf5c2e2018-01-06 23:30:04 -080094 /// A raw token literal not interpreted by Syn, possibly because it
95 /// represents an integer larger than 64 bits.
David Tolnay461d98e2018-01-07 11:07:19 -080096 ///
97 /// *This type is available if Syn is built with the `"derive"` or
98 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080099 pub Verbatim(LitVerbatim #manual_extra_traits {
100 pub token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -0800101 }),
102 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700103}
104
David Tolnay360efd22018-01-04 23:35:26 -0800105impl LitStr {
106 pub fn new(value: &str, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700107 let mut lit = Literal::string(value);
108 lit.set_span(span);
David Tolnay94d2b792018-04-29 12:26:10 -0700109 LitStr { token: lit }
David Tolnay360efd22018-01-04 23:35:26 -0800110 }
111
112 pub fn value(&self) -> String {
113 value::parse_lit_str(&self.token.to_string())
114 }
David Tolnayd53ac2b2018-01-27 19:00:06 -0800115
116 /// Parse a syntax tree node from the content of this string literal.
117 ///
118 /// All spans in the syntax tree will point to the span of this `LitStr`.
David Tolnay3b0444a2018-09-01 17:17:19 -0700119 ///
120 /// # Example
121 ///
David Tolnay95989db2019-01-01 15:05:57 -0500122 /// ```edition2018
David Tolnay3b0444a2018-09-01 17:17:19 -0700123 /// use proc_macro2::Span;
David Tolnay67fea042018-11-24 14:50:20 -0800124 /// use syn::{Attribute, Error, Ident, Lit, Meta, MetaNameValue, Path, Result};
David Tolnay3b0444a2018-09-01 17:17:19 -0700125 ///
126 /// // Parses the path from an attribute that looks like:
127 /// //
128 /// // #[path = "a::b::c"]
129 /// //
David Tolnay4ac734f2018-11-10 14:19:00 -0800130 /// // or returns `None` if the input is some other attribute.
131 /// fn get_path(attr: &Attribute) -> Result<Option<Path>> {
132 /// if !attr.path.is_ident("path") {
133 /// return Ok(None);
David Tolnay3b0444a2018-09-01 17:17:19 -0700134 /// }
135 ///
David Tolnay4ac734f2018-11-10 14:19:00 -0800136 /// match attr.parse_meta()? {
David Tolnay3b0444a2018-09-01 17:17:19 -0700137 /// Meta::NameValue(MetaNameValue { lit: Lit::Str(lit_str), .. }) => {
David Tolnay4ac734f2018-11-10 14:19:00 -0800138 /// lit_str.parse().map(Some)
David Tolnay3b0444a2018-09-01 17:17:19 -0700139 /// }
140 /// _ => {
David Tolnay3b0444a2018-09-01 17:17:19 -0700141 /// let message = "expected #[path = \"...\"]";
David Tolnayff853572019-03-07 22:04:15 -0800142 /// Err(Error::new_spanned(attr, message))
David Tolnay3b0444a2018-09-01 17:17:19 -0700143 /// }
144 /// }
145 /// }
146 /// ```
David Tolnayd53ac2b2018-01-27 19:00:06 -0800147 #[cfg(feature = "parsing")]
David Tolnay29e8d8c2019-03-07 22:43:15 -0800148 pub fn parse<T: Parse>(&self) -> Result<T> {
149 self.parse_with(T::parse)
150 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700151
David Tolnay29e8d8c2019-03-07 22:43:15 -0800152 /// Invoke parser on the content of this string literal.
153 ///
154 /// All spans in the syntax tree will point to the span of this `LitStr`.
155 ///
156 /// # Example
157 ///
158 /// ```edition2018
159 /// # use proc_macro2::Span;
160 /// # use syn::{LitStr, Result};
161 /// #
162 /// # fn main() -> Result<()> {
163 /// # let lit_str = LitStr::new("a::b::c", Span::call_site());
164 /// #
165 /// # const IGNORE: &str = stringify! {
166 /// let lit_str: LitStr = /* ... */;
167 /// # };
168 ///
169 /// // Parse a string literal like "a::b::c" into a Path, not allowing
170 /// // generic arguments on any of the path segments.
171 /// let basic_path = lit_str.parse_with(syn::Path::parse_mod_style)?;
172 /// #
173 /// # Ok(())
174 /// # }
175 /// ```
176 #[cfg(feature = "parsing")]
177 pub fn parse_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
178 use proc_macro2::Group;
David Tolnayd53ac2b2018-01-27 19:00:06 -0800179
180 // Token stream with every span replaced by the given one.
181 fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
David Tolnay94d2b792018-04-29 12:26:10 -0700182 stream
183 .into_iter()
184 .map(|token| respan_token_tree(token, span))
185 .collect()
David Tolnayd53ac2b2018-01-27 19:00:06 -0800186 }
187
188 // Token tree with every span replaced by the given one.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700189 fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
190 match token {
191 TokenTree::Group(ref mut g) => {
192 let stream = respan_token_stream(g.stream().clone(), span);
193 *g = Group::new(g.delimiter(), stream);
194 g.set_span(span);
195 }
196 ref mut other => other.set_span(span),
David Tolnayd53ac2b2018-01-27 19:00:06 -0800197 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700198 token
David Tolnayd53ac2b2018-01-27 19:00:06 -0800199 }
200
David Tolnay29e8d8c2019-03-07 22:43:15 -0800201 // Parse string literal into a token stream with every span equal to the
202 // original literal's span.
203 let mut tokens = ::parse_str(&self.value())?;
204 tokens = respan_token_stream(tokens, self.span());
205
206 parser.parse2(tokens)
David Tolnayd53ac2b2018-01-27 19:00:06 -0800207 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700208
209 pub fn span(&self) -> Span {
210 self.token.span()
211 }
212
213 pub fn set_span(&mut self, span: Span) {
214 self.token.set_span(span)
215 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700216}
217
David Tolnay360efd22018-01-04 23:35:26 -0800218impl LitByteStr {
219 pub fn new(value: &[u8], span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700220 let mut token = Literal::byte_string(value);
221 token.set_span(span);
222 LitByteStr { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800223 }
224
225 pub fn value(&self) -> Vec<u8> {
226 value::parse_lit_byte_str(&self.token.to_string())
227 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700228
229 pub fn span(&self) -> Span {
230 self.token.span()
231 }
232
233 pub fn set_span(&mut self, span: Span) {
234 self.token.set_span(span)
235 }
David Tolnay360efd22018-01-04 23:35:26 -0800236}
237
238impl LitByte {
239 pub fn new(value: u8, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700240 let mut token = Literal::u8_suffixed(value);
241 token.set_span(span);
242 LitByte { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800243 }
244
245 pub fn value(&self) -> u8 {
246 value::parse_lit_byte(&self.token.to_string())
247 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700248
249 pub fn span(&self) -> Span {
250 self.token.span()
251 }
252
253 pub fn set_span(&mut self, span: Span) {
254 self.token.set_span(span)
255 }
David Tolnay360efd22018-01-04 23:35:26 -0800256}
257
258impl LitChar {
259 pub fn new(value: char, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700260 let mut token = Literal::character(value);
261 token.set_span(span);
262 LitChar { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800263 }
264
265 pub fn value(&self) -> char {
266 value::parse_lit_char(&self.token.to_string())
267 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700268
269 pub fn span(&self) -> Span {
270 self.token.span()
271 }
272
273 pub fn set_span(&mut self, span: Span) {
274 self.token.set_span(span)
275 }
David Tolnay360efd22018-01-04 23:35:26 -0800276}
277
278impl LitInt {
279 pub fn new(value: u64, suffix: IntSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700280 let mut token = match suffix {
281 IntSuffix::Isize => Literal::isize_suffixed(value as isize),
282 IntSuffix::I8 => Literal::i8_suffixed(value as i8),
283 IntSuffix::I16 => Literal::i16_suffixed(value as i16),
284 IntSuffix::I32 => Literal::i32_suffixed(value as i32),
285 IntSuffix::I64 => Literal::i64_suffixed(value as i64),
286 IntSuffix::I128 => value::to_literal(&format!("{}i128", value)),
287 IntSuffix::Usize => Literal::usize_suffixed(value as usize),
288 IntSuffix::U8 => Literal::u8_suffixed(value as u8),
289 IntSuffix::U16 => Literal::u16_suffixed(value as u16),
290 IntSuffix::U32 => Literal::u32_suffixed(value as u32),
291 IntSuffix::U64 => Literal::u64_suffixed(value),
292 IntSuffix::U128 => value::to_literal(&format!("{}u128", value)),
293 IntSuffix::None => Literal::u64_unsuffixed(value),
294 };
295 token.set_span(span);
296 LitInt { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800297 }
298
299 pub fn value(&self) -> u64 {
300 value::parse_lit_int(&self.token.to_string()).unwrap()
301 }
302
303 pub fn suffix(&self) -> IntSuffix {
304 let value = self.token.to_string();
305 for (s, suffix) in vec![
306 ("i8", IntSuffix::I8),
307 ("i16", IntSuffix::I16),
308 ("i32", IntSuffix::I32),
309 ("i64", IntSuffix::I64),
310 ("i128", IntSuffix::I128),
311 ("isize", IntSuffix::Isize),
312 ("u8", IntSuffix::U8),
313 ("u16", IntSuffix::U16),
314 ("u32", IntSuffix::U32),
315 ("u64", IntSuffix::U64),
316 ("u128", IntSuffix::U128),
317 ("usize", IntSuffix::Usize),
318 ] {
319 if value.ends_with(s) {
320 return suffix;
321 }
322 }
323 IntSuffix::None
324 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700325
326 pub fn span(&self) -> Span {
327 self.token.span()
328 }
329
330 pub fn set_span(&mut self, span: Span) {
331 self.token.set_span(span)
332 }
David Tolnay360efd22018-01-04 23:35:26 -0800333}
334
335impl LitFloat {
336 pub fn new(value: f64, suffix: FloatSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700337 let mut token = match suffix {
338 FloatSuffix::F32 => Literal::f32_suffixed(value as f32),
339 FloatSuffix::F64 => Literal::f64_suffixed(value),
340 FloatSuffix::None => Literal::f64_unsuffixed(value),
341 };
342 token.set_span(span);
343 LitFloat { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800344 }
345
346 pub fn value(&self) -> f64 {
347 value::parse_lit_float(&self.token.to_string())
348 }
349
350 pub fn suffix(&self) -> FloatSuffix {
351 let value = self.token.to_string();
David Tolnay61037c62018-01-05 16:21:03 -0800352 for (s, suffix) in vec![("f32", FloatSuffix::F32), ("f64", FloatSuffix::F64)] {
David Tolnay360efd22018-01-04 23:35:26 -0800353 if value.ends_with(s) {
354 return suffix;
355 }
356 }
357 FloatSuffix::None
358 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700359
360 pub fn span(&self) -> Span {
361 self.token.span()
362 }
363
364 pub fn set_span(&mut self, span: Span) {
365 self.token.set_span(span)
366 }
David Tolnay360efd22018-01-04 23:35:26 -0800367}
368
369macro_rules! lit_extra_traits {
370 ($ty:ident, $field:ident) => {
371 #[cfg(feature = "extra-traits")]
372 impl Eq for $ty {}
373
374 #[cfg(feature = "extra-traits")]
375 impl PartialEq for $ty {
376 fn eq(&self, other: &Self) -> bool {
377 self.$field.to_string() == other.$field.to_string()
378 }
379 }
380
381 #[cfg(feature = "extra-traits")]
382 impl Hash for $ty {
383 fn hash<H>(&self, state: &mut H)
384 where
385 H: Hasher,
386 {
387 self.$field.to_string().hash(state);
388 }
David Tolnay9c76bcb2017-12-26 23:14:59 -0500389 }
David Tolnay6a170ce2018-08-26 22:29:24 -0700390
391 #[cfg(feature = "parsing")]
392 #[doc(hidden)]
393 #[allow(non_snake_case)]
394 pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
395 match marker {}
396 }
David Tolnay94d2b792018-04-29 12:26:10 -0700397 };
David Tolnayf4bbbd92016-09-23 14:41:55 -0700398}
399
Alex Crichton9a4dca22018-03-28 06:32:19 -0700400impl LitVerbatim {
401 pub fn span(&self) -> Span {
402 self.token.span()
403 }
404
405 pub fn set_span(&mut self, span: Span) {
406 self.token.set_span(span)
407 }
408}
409
David Tolnay360efd22018-01-04 23:35:26 -0800410lit_extra_traits!(LitStr, token);
411lit_extra_traits!(LitByteStr, token);
412lit_extra_traits!(LitByte, token);
413lit_extra_traits!(LitChar, token);
414lit_extra_traits!(LitInt, token);
415lit_extra_traits!(LitFloat, token);
416lit_extra_traits!(LitBool, value);
417lit_extra_traits!(LitVerbatim, token);
418
419ast_enum! {
David Tolnay05658502018-01-07 09:56:37 -0800420 /// The style of a string literal, either plain quoted or a raw string like
David Tolnayabf5c2e2018-01-06 23:30:04 -0800421 /// `r##"data"##`.
David Tolnay461d98e2018-01-07 11:07:19 -0800422 ///
423 /// *This type is available if Syn is built with the `"derive"` or `"full"`
424 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800425 pub enum StrStyle #no_visit {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800426 /// An ordinary string like `"data"`.
David Tolnay360efd22018-01-04 23:35:26 -0800427 Cooked,
David Tolnayabf5c2e2018-01-06 23:30:04 -0800428 /// A raw string like `r##"data"##`.
David Tolnay360efd22018-01-04 23:35:26 -0800429 ///
430 /// The unsigned integer is the number of `#` symbols used.
431 Raw(usize),
Alex Crichton62a0a592017-05-22 13:58:53 -0700432 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700433}
434
David Tolnay360efd22018-01-04 23:35:26 -0800435ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800436 /// The suffix on an integer literal if any, like the `u8` in `127u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800437 ///
438 /// *This type is available if Syn is built with the `"derive"` or `"full"`
439 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800440 pub enum IntSuffix #no_visit {
441 I8,
442 I16,
443 I32,
444 I64,
445 I128,
446 Isize,
447 U8,
448 U16,
449 U32,
450 U64,
451 U128,
452 Usize,
453 None,
Pascal Hertleif36342c52016-10-19 10:31:42 +0200454 }
455}
456
David Tolnay360efd22018-01-04 23:35:26 -0800457ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800458 /// The suffix on a floating point literal if any, like the `f32` in
459 /// `1.0f32`.
David Tolnay461d98e2018-01-07 11:07:19 -0800460 ///
461 /// *This type is available if Syn is built with the `"derive"` or `"full"`
462 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800463 pub enum FloatSuffix #no_visit {
464 F32,
465 F64,
466 None,
Alex Crichton2e0229c2017-05-23 09:34:50 -0700467 }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800468}
469
470#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400471#[doc(hidden)]
472#[allow(non_snake_case)]
473pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
474 match marker {}
475}
476
477#[cfg(feature = "parsing")]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700478pub mod parsing {
479 use super::*;
David Tolnay4fb71232018-08-25 23:14:50 -0400480 use parse::{Parse, ParseStream, Result};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700481
David Tolnay4fb71232018-08-25 23:14:50 -0400482 impl Parse for Lit {
483 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay924e0af2018-09-01 13:07:34 -0700484 input.step(|cursor| {
485 if let Some((lit, rest)) = cursor.literal() {
486 return Ok((Lit::new(lit), rest));
487 }
488 while let Some((ident, rest)) = cursor.ident() {
489 let value = if ident == "true" {
490 true
491 } else if ident == "false" {
492 false
493 } else {
494 break;
495 };
496 let lit_bool = LitBool {
497 value: value,
498 span: ident.span(),
499 };
500 return Ok((Lit::Bool(lit_bool), rest));
501 }
502 Err(cursor.error("expected literal"))
David Tolnay4fb71232018-08-25 23:14:50 -0400503 })
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800504 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700505 }
David Tolnay360efd22018-01-04 23:35:26 -0800506
David Tolnaya7d69fc2018-08-26 13:30:24 -0400507 impl Parse for LitStr {
508 fn parse(input: ParseStream) -> Result<Self> {
509 let head = input.fork();
510 match input.parse()? {
511 Lit::Str(lit) => Ok(lit),
512 _ => Err(head.error("expected string literal")),
513 }
514 }
515 }
David Tolnay360efd22018-01-04 23:35:26 -0800516
David Tolnaya7d69fc2018-08-26 13:30:24 -0400517 impl Parse for LitByteStr {
518 fn parse(input: ParseStream) -> Result<Self> {
519 let head = input.fork();
520 match input.parse()? {
521 Lit::ByteStr(lit) => Ok(lit),
522 _ => Err(head.error("expected byte string literal")),
523 }
524 }
525 }
David Tolnay360efd22018-01-04 23:35:26 -0800526
David Tolnaya7d69fc2018-08-26 13:30:24 -0400527 impl Parse for LitByte {
528 fn parse(input: ParseStream) -> Result<Self> {
529 let head = input.fork();
530 match input.parse()? {
531 Lit::Byte(lit) => Ok(lit),
532 _ => Err(head.error("expected byte literal")),
533 }
534 }
535 }
David Tolnay360efd22018-01-04 23:35:26 -0800536
David Tolnaya7d69fc2018-08-26 13:30:24 -0400537 impl Parse for LitChar {
538 fn parse(input: ParseStream) -> Result<Self> {
539 let head = input.fork();
540 match input.parse()? {
541 Lit::Char(lit) => Ok(lit),
542 _ => Err(head.error("expected character literal")),
543 }
544 }
545 }
David Tolnay360efd22018-01-04 23:35:26 -0800546
David Tolnaya7d69fc2018-08-26 13:30:24 -0400547 impl Parse for LitInt {
548 fn parse(input: ParseStream) -> Result<Self> {
549 let head = input.fork();
550 match input.parse()? {
551 Lit::Int(lit) => Ok(lit),
552 _ => Err(head.error("expected integer literal")),
553 }
554 }
555 }
David Tolnay360efd22018-01-04 23:35:26 -0800556
David Tolnaya7d69fc2018-08-26 13:30:24 -0400557 impl Parse for LitFloat {
558 fn parse(input: ParseStream) -> Result<Self> {
559 let head = input.fork();
560 match input.parse()? {
561 Lit::Float(lit) => Ok(lit),
562 _ => Err(head.error("expected floating point literal")),
563 }
564 }
565 }
David Tolnay360efd22018-01-04 23:35:26 -0800566
David Tolnaya7d69fc2018-08-26 13:30:24 -0400567 impl Parse for LitBool {
568 fn parse(input: ParseStream) -> Result<Self> {
569 let head = input.fork();
570 match input.parse()? {
571 Lit::Bool(lit) => Ok(lit),
572 _ => Err(head.error("expected boolean literal")),
573 }
574 }
575 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700576}
577
578#[cfg(feature = "printing")]
579mod printing {
580 use super::*;
Alex Crichtona74a1c82018-05-16 10:20:44 -0700581 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700582 use quote::{ToTokens, TokenStreamExt};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700583
David Tolnay360efd22018-01-04 23:35:26 -0800584 impl ToTokens for LitStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700585 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700586 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800587 }
588 }
589
590 impl ToTokens for LitByteStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700591 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700592 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800593 }
594 }
595
596 impl ToTokens for LitByte {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700597 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700598 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800599 }
600 }
601
602 impl ToTokens for LitChar {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700603 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700604 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800605 }
606 }
607
608 impl ToTokens for LitInt {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700609 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700610 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800611 }
612 }
613
614 impl ToTokens for LitFloat {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700615 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700616 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800617 }
618 }
619
620 impl ToTokens for LitBool {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700621 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700622 let s = if self.value { "true" } else { "false" };
Alex Crichtona74a1c82018-05-16 10:20:44 -0700623 tokens.append(Ident::new(s, self.span));
David Tolnay360efd22018-01-04 23:35:26 -0800624 }
625 }
626
627 impl ToTokens for LitVerbatim {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700628 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700629 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800630 }
631 }
632}
633
634mod value {
635 use super::*;
David Tolnay94d2b792018-04-29 12:26:10 -0700636 use proc_macro2::TokenStream;
David Tolnay360efd22018-01-04 23:35:26 -0800637 use std::char;
638 use std::ops::{Index, RangeFrom};
David Tolnay360efd22018-01-04 23:35:26 -0800639
David Tolnay7d1d1282018-01-06 16:10:51 -0800640 impl Lit {
David Tolnay780292d2018-01-22 23:26:44 -0800641 /// Interpret a Syn literal from a proc-macro2 literal.
642 ///
643 /// Not all proc-macro2 literals are valid Syn literals. In particular,
644 /// doc comments are considered by proc-macro2 to be literals but in Syn
645 /// they are [`Attribute`].
646 ///
647 /// [`Attribute`]: struct.Attribute.html
648 ///
649 /// # Panics
650 ///
651 /// Panics if the input is a doc comment literal.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700652 pub fn new(token: Literal) -> Self {
David Tolnay7d1d1282018-01-06 16:10:51 -0800653 let value = token.to_string();
654
655 match value::byte(&value, 0) {
David Tolnay94d2b792018-04-29 12:26:10 -0700656 b'"' | b'r' => return Lit::Str(LitStr { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800657 b'b' => match value::byte(&value, 1) {
David Tolnay94d2b792018-04-29 12:26:10 -0700658 b'"' | b'r' => return Lit::ByteStr(LitByteStr { token: token }),
659 b'\'' => return Lit::Byte(LitByte { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800660 _ => {}
661 },
David Tolnay94d2b792018-04-29 12:26:10 -0700662 b'\'' => return Lit::Char(LitChar { token: token }),
David Tolnayfb84fc02018-10-02 21:01:30 -0700663 b'0'...b'9' => {
664 if number_is_int(&value) {
665 return Lit::Int(LitInt { token: token });
666 } else if number_is_float(&value) {
667 return Lit::Float(LitFloat { token: token });
668 } else {
669 // number overflow
670 return Lit::Verbatim(LitVerbatim { token: token });
671 }
672 }
673 _ => {
674 if value == "true" || value == "false" {
675 return Lit::Bool(LitBool {
676 value: value == "true",
677 span: token.span(),
678 });
679 }
680 }
David Tolnay7d1d1282018-01-06 16:10:51 -0800681 }
682
683 panic!("Unrecognized literal: {}", value);
684 }
685 }
686
687 fn number_is_int(value: &str) -> bool {
688 if number_is_float(value) {
689 false
690 } else {
691 value::parse_lit_int(value).is_some()
692 }
693 }
694
695 fn number_is_float(value: &str) -> bool {
696 if value.contains('.') {
697 true
698 } else if value.starts_with("0x") || value.ends_with("size") {
699 false
700 } else {
701 value.contains('e') || value.contains('E')
702 }
703 }
704
David Tolnay360efd22018-01-04 23:35:26 -0800705 /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
706 /// past the end of the input buffer.
707 pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
708 let s = s.as_ref();
709 if idx < s.len() {
710 s[idx]
711 } else {
712 0
713 }
714 }
715
716 fn next_chr(s: &str) -> char {
717 s.chars().next().unwrap_or('\0')
718 }
719
720 pub fn parse_lit_str(s: &str) -> String {
721 match byte(s, 0) {
722 b'"' => parse_lit_str_cooked(s),
723 b'r' => parse_lit_str_raw(s),
724 _ => unreachable!(),
725 }
726 }
727
David Tolnay76ebcdd2018-01-05 17:07:26 -0800728 // Clippy false positive
729 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
730 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800731 fn parse_lit_str_cooked(mut s: &str) -> String {
732 assert_eq!(byte(s, 0), b'"');
733 s = &s[1..];
734
735 let mut out = String::new();
736 'outer: loop {
737 let ch = match byte(s, 0) {
738 b'"' => break,
739 b'\\' => {
740 let b = byte(s, 1);
741 s = &s[2..];
742 match b {
743 b'x' => {
744 let (byte, rest) = backslash_x(s);
745 s = rest;
746 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800747 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800748 }
749 b'u' => {
David Tolnay76ebcdd2018-01-05 17:07:26 -0800750 let (chr, rest) = backslash_u(s);
David Tolnay360efd22018-01-04 23:35:26 -0800751 s = rest;
752 chr
753 }
754 b'n' => '\n',
755 b'r' => '\r',
756 b't' => '\t',
757 b'\\' => '\\',
758 b'0' => '\0',
759 b'\'' => '\'',
760 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800761 b'\r' | b'\n' => loop {
762 let ch = next_chr(s);
763 if ch.is_whitespace() {
764 s = &s[ch.len_utf8()..];
765 } else {
766 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800767 }
David Tolnay61037c62018-01-05 16:21:03 -0800768 },
769 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800770 }
771 }
772 b'\r' => {
773 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
774 s = &s[2..];
775 '\n'
776 }
777 _ => {
778 let ch = next_chr(s);
779 s = &s[ch.len_utf8()..];
780 ch
781 }
782 };
783 out.push(ch);
784 }
785
786 assert_eq!(s, "\"");
787 out
788 }
789
790 fn parse_lit_str_raw(mut s: &str) -> String {
791 assert_eq!(byte(s, 0), b'r');
792 s = &s[1..];
793
794 let mut pounds = 0;
795 while byte(s, pounds) == b'#' {
796 pounds += 1;
797 }
798 assert_eq!(byte(s, pounds), b'"');
799 assert_eq!(byte(s, s.len() - pounds - 1), b'"');
800 for end in s[s.len() - pounds..].bytes() {
801 assert_eq!(end, b'#');
802 }
803
804 s[pounds + 1..s.len() - pounds - 1].to_owned()
805 }
806
807 pub fn parse_lit_byte_str(s: &str) -> Vec<u8> {
808 assert_eq!(byte(s, 0), b'b');
809 match byte(s, 1) {
810 b'"' => parse_lit_byte_str_cooked(s),
811 b'r' => parse_lit_byte_str_raw(s),
812 _ => unreachable!(),
813 }
814 }
815
David Tolnay76ebcdd2018-01-05 17:07:26 -0800816 // Clippy false positive
817 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
818 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800819 fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> {
820 assert_eq!(byte(s, 0), b'b');
821 assert_eq!(byte(s, 1), b'"');
822 s = &s[2..];
823
824 // We're going to want to have slices which don't respect codepoint boundaries.
825 let mut s = s.as_bytes();
826
827 let mut out = Vec::new();
828 'outer: loop {
829 let byte = match byte(s, 0) {
830 b'"' => break,
831 b'\\' => {
832 let b = byte(s, 1);
833 s = &s[2..];
834 match b {
835 b'x' => {
836 let (b, rest) = backslash_x(s);
837 s = rest;
838 b
839 }
840 b'n' => b'\n',
841 b'r' => b'\r',
842 b't' => b'\t',
843 b'\\' => b'\\',
844 b'0' => b'\0',
845 b'\'' => b'\'',
846 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800847 b'\r' | b'\n' => loop {
848 let byte = byte(s, 0);
David Tolnay76ebcdd2018-01-05 17:07:26 -0800849 let ch = char::from_u32(u32::from(byte)).unwrap();
David Tolnay61037c62018-01-05 16:21:03 -0800850 if ch.is_whitespace() {
851 s = &s[1..];
852 } else {
853 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800854 }
David Tolnay61037c62018-01-05 16:21:03 -0800855 },
856 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800857 }
858 }
859 b'\r' => {
860 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
861 s = &s[2..];
862 b'\n'
863 }
864 b => {
865 s = &s[1..];
866 b
867 }
868 };
869 out.push(byte);
870 }
871
872 assert_eq!(s, b"\"");
873 out
874 }
875
876 fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> {
877 assert_eq!(byte(s, 0), b'b');
878 parse_lit_str_raw(&s[1..]).into_bytes()
879 }
880
881 pub fn parse_lit_byte(s: &str) -> u8 {
882 assert_eq!(byte(s, 0), b'b');
883 assert_eq!(byte(s, 1), b'\'');
884
885 // We're going to want to have slices which don't respect codepoint boundaries.
886 let mut s = s[2..].as_bytes();
887
888 let b = match byte(s, 0) {
889 b'\\' => {
890 let b = byte(s, 1);
891 s = &s[2..];
892 match b {
893 b'x' => {
894 let (b, rest) = backslash_x(s);
895 s = rest;
896 b
897 }
898 b'n' => b'\n',
899 b'r' => b'\r',
900 b't' => b'\t',
901 b'\\' => b'\\',
902 b'0' => b'\0',
903 b'\'' => b'\'',
904 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800905 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800906 }
907 }
908 b => {
909 s = &s[1..];
910 b
911 }
912 };
913
914 assert_eq!(byte(s, 0), b'\'');
915 b
916 }
917
918 pub fn parse_lit_char(mut s: &str) -> char {
919 assert_eq!(byte(s, 0), b'\'');
920 s = &s[1..];
921
922 let ch = match byte(s, 0) {
923 b'\\' => {
924 let b = byte(s, 1);
925 s = &s[2..];
926 match b {
927 b'x' => {
928 let (byte, rest) = backslash_x(s);
929 s = rest;
930 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800931 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800932 }
933 b'u' => {
934 let (chr, rest) = backslash_u(s);
935 s = rest;
936 chr
937 }
938 b'n' => '\n',
939 b'r' => '\r',
940 b't' => '\t',
941 b'\\' => '\\',
942 b'0' => '\0',
943 b'\'' => '\'',
944 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800945 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800946 }
947 }
948 _ => {
949 let ch = next_chr(s);
950 s = &s[ch.len_utf8()..];
951 ch
952 }
953 };
954 assert_eq!(s, "\'", "Expected end of char literal");
955 ch
956 }
957
958 fn backslash_x<S>(s: &S) -> (u8, &S)
David Tolnay61037c62018-01-05 16:21:03 -0800959 where
960 S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
David Tolnay360efd22018-01-04 23:35:26 -0800961 {
962 let mut ch = 0;
963 let b0 = byte(s, 0);
964 let b1 = byte(s, 1);
David Tolnaye614f282018-10-27 22:50:12 -0700965 ch += 0x10
966 * match b0 {
967 b'0'...b'9' => b0 - b'0',
968 b'a'...b'f' => 10 + (b0 - b'a'),
969 b'A'...b'F' => 10 + (b0 - b'A'),
970 _ => panic!("unexpected non-hex character after \\x"),
971 };
David Tolnay76ebcdd2018-01-05 17:07:26 -0800972 ch += match b1 {
David Tolnay360efd22018-01-04 23:35:26 -0800973 b'0'...b'9' => b1 - b'0',
974 b'a'...b'f' => 10 + (b1 - b'a'),
975 b'A'...b'F' => 10 + (b1 - b'A'),
976 _ => panic!("unexpected non-hex character after \\x"),
977 };
978 (ch, &s[2..])
979 }
980
981 fn backslash_u(mut s: &str) -> (char, &str) {
982 if byte(s, 0) != b'{' {
983 panic!("expected {{ after \\u");
984 }
985 s = &s[1..];
986
987 let mut ch = 0;
988 for _ in 0..6 {
989 let b = byte(s, 0);
990 match b {
991 b'0'...b'9' => {
992 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800993 ch += u32::from(b - b'0');
David Tolnay360efd22018-01-04 23:35:26 -0800994 s = &s[1..];
995 }
996 b'a'...b'f' => {
997 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800998 ch += u32::from(10 + b - b'a');
David Tolnay360efd22018-01-04 23:35:26 -0800999 s = &s[1..];
1000 }
1001 b'A'...b'F' => {
1002 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -08001003 ch += u32::from(10 + b - b'A');
David Tolnay360efd22018-01-04 23:35:26 -08001004 s = &s[1..];
1005 }
1006 b'}' => break,
1007 _ => panic!("unexpected non-hex character after \\u"),
1008 }
1009 }
1010 assert!(byte(s, 0) == b'}');
1011 s = &s[1..];
1012
1013 if let Some(ch) = char::from_u32(ch) {
1014 (ch, s)
1015 } else {
1016 panic!("character code {:x} is not a valid unicode character", ch);
1017 }
1018 }
1019
1020 pub fn parse_lit_int(mut s: &str) -> Option<u64> {
1021 let base = match (byte(s, 0), byte(s, 1)) {
1022 (b'0', b'x') => {
1023 s = &s[2..];
1024 16
1025 }
1026 (b'0', b'o') => {
1027 s = &s[2..];
1028 8
1029 }
1030 (b'0', b'b') => {
1031 s = &s[2..];
1032 2
1033 }
1034 (b'0'...b'9', _) => 10,
1035 _ => unreachable!(),
1036 };
1037
1038 let mut value = 0u64;
1039 loop {
1040 let b = byte(s, 0);
1041 let digit = match b {
David Tolnay76ebcdd2018-01-05 17:07:26 -08001042 b'0'...b'9' => u64::from(b - b'0'),
1043 b'a'...b'f' if base > 10 => 10 + u64::from(b - b'a'),
1044 b'A'...b'F' if base > 10 => 10 + u64::from(b - b'A'),
David Tolnay360efd22018-01-04 23:35:26 -08001045 b'_' => {
1046 s = &s[1..];
1047 continue;
1048 }
1049 // NOTE: Looking at a floating point literal, we don't want to
1050 // consider these integers.
1051 b'.' if base == 10 => return None,
1052 b'e' | b'E' if base == 10 => return None,
1053 _ => break,
1054 };
1055
1056 if digit >= base {
1057 panic!("Unexpected digit {:x} out of base range", digit);
1058 }
1059
1060 value = match value.checked_mul(base) {
1061 Some(value) => value,
1062 None => return None,
1063 };
1064 value = match value.checked_add(digit) {
1065 Some(value) => value,
1066 None => return None,
1067 };
1068 s = &s[1..];
1069 }
1070
1071 Some(value)
1072 }
1073
1074 pub fn parse_lit_float(input: &str) -> f64 {
1075 // Rust's floating point literals are very similar to the ones parsed by
1076 // the standard library, except that rust's literals can contain
1077 // ignorable underscores. Let's remove those underscores.
1078 let mut bytes = input.to_owned().into_bytes();
1079 let mut write = 0;
1080 for read in 0..bytes.len() {
1081 if bytes[read] == b'_' {
1082 continue; // Don't increase write
David Tolnay76ebcdd2018-01-05 17:07:26 -08001083 }
1084 if write != read {
David Tolnay360efd22018-01-04 23:35:26 -08001085 let x = bytes[read];
1086 bytes[write] = x;
1087 }
1088 write += 1;
1089 }
1090 bytes.truncate(write);
1091 let input = String::from_utf8(bytes).unwrap();
David Tolnay76ebcdd2018-01-05 17:07:26 -08001092 let end = input.find('f').unwrap_or_else(|| input.len());
David Tolnay360efd22018-01-04 23:35:26 -08001093 input[..end].parse().unwrap()
1094 }
1095
1096 pub fn to_literal(s: &str) -> Literal {
1097 let stream = s.parse::<TokenStream>().unwrap();
Alex Crichton9a4dca22018-03-28 06:32:19 -07001098 match stream.into_iter().next().unwrap() {
1099 TokenTree::Literal(l) => l,
David Tolnay360efd22018-01-04 23:35:26 -08001100 _ => unreachable!(),
David Tolnayf17fd2f2016-10-07 23:38:08 -07001101 }
1102 }
David Tolnayf4bbbd92016-09-23 14:41:55 -07001103}