blob: fc7284effa4ed32d103c9632ea1bcadd8d3fa873 [file] [log] [blame]
David Tolnay55535012018-01-05 16:39:23 -08001// Copyright 2018 Syn Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
Alex Crichton9a4dca22018-03-28 06:32:19 -07009use proc_macro2::{Literal, Span};
David Tolnay360efd22018-01-04 23:35:26 -080010use std::str;
11
David Tolnay7d1d1282018-01-06 16:10:51 -080012#[cfg(feature = "printing")]
Alex Crichtona74a1c82018-05-16 10:20:44 -070013use proc_macro2::Ident;
David Tolnay7d1d1282018-01-06 16:10:51 -080014
David Tolnayd53ac2b2018-01-27 19:00:06 -080015#[cfg(feature = "parsing")]
16use proc_macro2::TokenStream;
17#[cfg(feature = "parsing")]
David Tolnaye82a2b12018-08-30 16:31:10 -070018use Error;
David Tolnayd53ac2b2018-01-27 19:00:06 -080019
David Tolnay60fafad2018-02-03 09:18:03 -080020use proc_macro2::TokenTree;
21
David Tolnay360efd22018-01-04 23:35:26 -080022#[cfg(feature = "extra-traits")]
Alex Crichtonccbb45d2017-05-23 10:58:24 -070023use std::hash::{Hash, Hasher};
24
David Tolnay4fb71232018-08-25 23:14:50 -040025#[cfg(feature = "parsing")]
26use lookahead;
David Tolnaye82a2b12018-08-30 16:31:10 -070027#[cfg(feature = "parsing")]
28use parse::Parse;
David Tolnay4fb71232018-08-25 23:14:50 -040029
David Tolnay360efd22018-01-04 23:35:26 -080030ast_enum_of_structs! {
David Tolnayabf5c2e2018-01-06 23:30:04 -080031 /// A Rust literal such as a string or integer or boolean.
David Tolnay614a0142018-01-07 10:25:43 -080032 ///
David Tolnay461d98e2018-01-07 11:07:19 -080033 /// *This type is available if Syn is built with the `"derive"` or `"full"`
34 /// feature.*
35 ///
David Tolnay614a0142018-01-07 10:25:43 -080036 /// # Syntax tree enum
37 ///
38 /// This type is a [syntax tree enum].
39 ///
40 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
David Tolnay360efd22018-01-04 23:35:26 -080041 pub enum Lit {
David Tolnayabf5c2e2018-01-06 23:30:04 -080042 /// A UTF-8 string literal: `"foo"`.
David Tolnay461d98e2018-01-07 11:07:19 -080043 ///
44 /// *This type is available if Syn is built with the `"derive"` or
45 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080046 pub Str(LitStr #manual_extra_traits {
47 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080048 }),
Alex Crichtonccbb45d2017-05-23 10:58:24 -070049
David Tolnayabf5c2e2018-01-06 23:30:04 -080050 /// A byte string literal: `b"foo"`.
David Tolnay461d98e2018-01-07 11:07:19 -080051 ///
52 /// *This type is available if Syn is built with the `"derive"` or
53 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080054 pub ByteStr(LitByteStr #manual_extra_traits {
55 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080056 }),
57
David Tolnayabf5c2e2018-01-06 23:30:04 -080058 /// A byte literal: `b'f'`.
David Tolnay461d98e2018-01-07 11:07:19 -080059 ///
60 /// *This type is available if Syn is built with the `"derive"` or
61 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080062 pub Byte(LitByte #manual_extra_traits {
63 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080064 }),
65
David Tolnayabf5c2e2018-01-06 23:30:04 -080066 /// A character literal: `'a'`.
David Tolnay461d98e2018-01-07 11:07:19 -080067 ///
68 /// *This type is available if Syn is built with the `"derive"` or
69 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080070 pub Char(LitChar #manual_extra_traits {
71 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080072 }),
73
David Tolnayabf5c2e2018-01-06 23:30:04 -080074 /// An integer literal: `1` or `1u16`.
David Tolnay360efd22018-01-04 23:35:26 -080075 ///
76 /// Holds up to 64 bits of data. Use `LitVerbatim` for any larger
77 /// integer literal.
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 Int(LitInt #manual_extra_traits {
82 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080083 }),
84
David Tolnayabf5c2e2018-01-06 23:30:04 -080085 /// A floating point literal: `1f64` or `1.0e10f64`.
David Tolnay360efd22018-01-04 23:35:26 -080086 ///
87 /// Must be finite. May not be infinte or NaN.
David Tolnay461d98e2018-01-07 11:07:19 -080088 ///
89 /// *This type is available if Syn is built with the `"derive"` or
90 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080091 pub Float(LitFloat #manual_extra_traits {
92 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080093 }),
94
David Tolnayabf5c2e2018-01-06 23:30:04 -080095 /// A boolean literal: `true` or `false`.
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 Bool(LitBool #manual_extra_traits {
100 pub value: bool,
101 pub span: Span,
102 }),
103
David Tolnayabf5c2e2018-01-06 23:30:04 -0800104 /// A raw token literal not interpreted by Syn, possibly because it
105 /// represents an integer larger than 64 bits.
David Tolnay461d98e2018-01-07 11:07:19 -0800106 ///
107 /// *This type is available if Syn is built with the `"derive"` or
108 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800109 pub Verbatim(LitVerbatim #manual_extra_traits {
110 pub token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -0800111 }),
112 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700113}
114
David Tolnay360efd22018-01-04 23:35:26 -0800115impl LitStr {
116 pub fn new(value: &str, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700117 let mut lit = Literal::string(value);
118 lit.set_span(span);
David Tolnay94d2b792018-04-29 12:26:10 -0700119 LitStr { token: lit }
David Tolnay360efd22018-01-04 23:35:26 -0800120 }
121
122 pub fn value(&self) -> String {
123 value::parse_lit_str(&self.token.to_string())
124 }
David Tolnayd53ac2b2018-01-27 19:00:06 -0800125
126 /// Parse a syntax tree node from the content of this string literal.
127 ///
128 /// All spans in the syntax tree will point to the span of this `LitStr`.
129 #[cfg(feature = "parsing")]
David Tolnaye82a2b12018-08-30 16:31:10 -0700130 pub fn parse<T: Parse>(&self) -> Result<T, Error> {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700131 use proc_macro2::Group;
132
David Tolnayd53ac2b2018-01-27 19:00:06 -0800133 // Parse string literal into a token stream with every span equal to the
134 // original literal's span.
David Tolnayad4b2472018-08-25 08:25:24 -0400135 fn spanned_tokens(s: &LitStr) -> Result<TokenStream, Error> {
David Tolnayd53ac2b2018-01-27 19:00:06 -0800136 let stream = ::parse_str(&s.value())?;
Alex Crichton9a4dca22018-03-28 06:32:19 -0700137 Ok(respan_token_stream(stream, s.span()))
David Tolnayd53ac2b2018-01-27 19:00:06 -0800138 }
139
140 // Token stream with every span replaced by the given one.
141 fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
David Tolnay94d2b792018-04-29 12:26:10 -0700142 stream
143 .into_iter()
144 .map(|token| respan_token_tree(token, span))
145 .collect()
David Tolnayd53ac2b2018-01-27 19:00:06 -0800146 }
147
148 // Token tree with every span replaced by the given one.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700149 fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
150 match token {
151 TokenTree::Group(ref mut g) => {
152 let stream = respan_token_stream(g.stream().clone(), span);
153 *g = Group::new(g.delimiter(), stream);
154 g.set_span(span);
155 }
156 ref mut other => other.set_span(span),
David Tolnayd53ac2b2018-01-27 19:00:06 -0800157 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700158 token
David Tolnayd53ac2b2018-01-27 19:00:06 -0800159 }
160
161 spanned_tokens(self).and_then(::parse2)
162 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700163
164 pub fn span(&self) -> Span {
165 self.token.span()
166 }
167
168 pub fn set_span(&mut self, span: Span) {
169 self.token.set_span(span)
170 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700171}
172
David Tolnay360efd22018-01-04 23:35:26 -0800173impl LitByteStr {
174 pub fn new(value: &[u8], span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700175 let mut token = Literal::byte_string(value);
176 token.set_span(span);
177 LitByteStr { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800178 }
179
180 pub fn value(&self) -> Vec<u8> {
181 value::parse_lit_byte_str(&self.token.to_string())
182 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700183
184 pub fn span(&self) -> Span {
185 self.token.span()
186 }
187
188 pub fn set_span(&mut self, span: Span) {
189 self.token.set_span(span)
190 }
David Tolnay360efd22018-01-04 23:35:26 -0800191}
192
193impl LitByte {
194 pub fn new(value: u8, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700195 let mut token = Literal::u8_suffixed(value);
196 token.set_span(span);
197 LitByte { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800198 }
199
200 pub fn value(&self) -> u8 {
201 value::parse_lit_byte(&self.token.to_string())
202 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700203
204 pub fn span(&self) -> Span {
205 self.token.span()
206 }
207
208 pub fn set_span(&mut self, span: Span) {
209 self.token.set_span(span)
210 }
David Tolnay360efd22018-01-04 23:35:26 -0800211}
212
213impl LitChar {
214 pub fn new(value: char, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700215 let mut token = Literal::character(value);
216 token.set_span(span);
217 LitChar { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800218 }
219
220 pub fn value(&self) -> char {
221 value::parse_lit_char(&self.token.to_string())
222 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700223
224 pub fn span(&self) -> Span {
225 self.token.span()
226 }
227
228 pub fn set_span(&mut self, span: Span) {
229 self.token.set_span(span)
230 }
David Tolnay360efd22018-01-04 23:35:26 -0800231}
232
233impl LitInt {
234 pub fn new(value: u64, suffix: IntSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700235 let mut token = match suffix {
236 IntSuffix::Isize => Literal::isize_suffixed(value as isize),
237 IntSuffix::I8 => Literal::i8_suffixed(value as i8),
238 IntSuffix::I16 => Literal::i16_suffixed(value as i16),
239 IntSuffix::I32 => Literal::i32_suffixed(value as i32),
240 IntSuffix::I64 => Literal::i64_suffixed(value as i64),
241 IntSuffix::I128 => value::to_literal(&format!("{}i128", value)),
242 IntSuffix::Usize => Literal::usize_suffixed(value as usize),
243 IntSuffix::U8 => Literal::u8_suffixed(value as u8),
244 IntSuffix::U16 => Literal::u16_suffixed(value as u16),
245 IntSuffix::U32 => Literal::u32_suffixed(value as u32),
246 IntSuffix::U64 => Literal::u64_suffixed(value),
247 IntSuffix::U128 => value::to_literal(&format!("{}u128", value)),
248 IntSuffix::None => Literal::u64_unsuffixed(value),
249 };
250 token.set_span(span);
251 LitInt { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800252 }
253
254 pub fn value(&self) -> u64 {
255 value::parse_lit_int(&self.token.to_string()).unwrap()
256 }
257
258 pub fn suffix(&self) -> IntSuffix {
259 let value = self.token.to_string();
260 for (s, suffix) in vec![
261 ("i8", IntSuffix::I8),
262 ("i16", IntSuffix::I16),
263 ("i32", IntSuffix::I32),
264 ("i64", IntSuffix::I64),
265 ("i128", IntSuffix::I128),
266 ("isize", IntSuffix::Isize),
267 ("u8", IntSuffix::U8),
268 ("u16", IntSuffix::U16),
269 ("u32", IntSuffix::U32),
270 ("u64", IntSuffix::U64),
271 ("u128", IntSuffix::U128),
272 ("usize", IntSuffix::Usize),
273 ] {
274 if value.ends_with(s) {
275 return suffix;
276 }
277 }
278 IntSuffix::None
279 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700280
281 pub fn span(&self) -> Span {
282 self.token.span()
283 }
284
285 pub fn set_span(&mut self, span: Span) {
286 self.token.set_span(span)
287 }
David Tolnay360efd22018-01-04 23:35:26 -0800288}
289
290impl LitFloat {
291 pub fn new(value: f64, suffix: FloatSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700292 let mut token = match suffix {
293 FloatSuffix::F32 => Literal::f32_suffixed(value as f32),
294 FloatSuffix::F64 => Literal::f64_suffixed(value),
295 FloatSuffix::None => Literal::f64_unsuffixed(value),
296 };
297 token.set_span(span);
298 LitFloat { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800299 }
300
301 pub fn value(&self) -> f64 {
302 value::parse_lit_float(&self.token.to_string())
303 }
304
305 pub fn suffix(&self) -> FloatSuffix {
306 let value = self.token.to_string();
David Tolnay61037c62018-01-05 16:21:03 -0800307 for (s, suffix) in vec![("f32", FloatSuffix::F32), ("f64", FloatSuffix::F64)] {
David Tolnay360efd22018-01-04 23:35:26 -0800308 if value.ends_with(s) {
309 return suffix;
310 }
311 }
312 FloatSuffix::None
313 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700314
315 pub fn span(&self) -> Span {
316 self.token.span()
317 }
318
319 pub fn set_span(&mut self, span: Span) {
320 self.token.set_span(span)
321 }
David Tolnay360efd22018-01-04 23:35:26 -0800322}
323
324macro_rules! lit_extra_traits {
325 ($ty:ident, $field:ident) => {
326 #[cfg(feature = "extra-traits")]
327 impl Eq for $ty {}
328
329 #[cfg(feature = "extra-traits")]
330 impl PartialEq for $ty {
331 fn eq(&self, other: &Self) -> bool {
332 self.$field.to_string() == other.$field.to_string()
333 }
334 }
335
336 #[cfg(feature = "extra-traits")]
337 impl Hash for $ty {
338 fn hash<H>(&self, state: &mut H)
339 where
340 H: Hasher,
341 {
342 self.$field.to_string().hash(state);
343 }
David Tolnay9c76bcb2017-12-26 23:14:59 -0500344 }
David Tolnay6a170ce2018-08-26 22:29:24 -0700345
346 #[cfg(feature = "parsing")]
347 #[doc(hidden)]
348 #[allow(non_snake_case)]
349 pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
350 match marker {}
351 }
David Tolnay94d2b792018-04-29 12:26:10 -0700352 };
David Tolnayf4bbbd92016-09-23 14:41:55 -0700353}
354
Alex Crichton9a4dca22018-03-28 06:32:19 -0700355impl LitVerbatim {
356 pub fn span(&self) -> Span {
357 self.token.span()
358 }
359
360 pub fn set_span(&mut self, span: Span) {
361 self.token.set_span(span)
362 }
363}
364
David Tolnay360efd22018-01-04 23:35:26 -0800365lit_extra_traits!(LitStr, token);
366lit_extra_traits!(LitByteStr, token);
367lit_extra_traits!(LitByte, token);
368lit_extra_traits!(LitChar, token);
369lit_extra_traits!(LitInt, token);
370lit_extra_traits!(LitFloat, token);
371lit_extra_traits!(LitBool, value);
372lit_extra_traits!(LitVerbatim, token);
373
374ast_enum! {
David Tolnay05658502018-01-07 09:56:37 -0800375 /// The style of a string literal, either plain quoted or a raw string like
David Tolnayabf5c2e2018-01-06 23:30:04 -0800376 /// `r##"data"##`.
David Tolnay461d98e2018-01-07 11:07:19 -0800377 ///
378 /// *This type is available if Syn is built with the `"derive"` or `"full"`
379 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800380 pub enum StrStyle #no_visit {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800381 /// An ordinary string like `"data"`.
David Tolnay360efd22018-01-04 23:35:26 -0800382 Cooked,
David Tolnayabf5c2e2018-01-06 23:30:04 -0800383 /// A raw string like `r##"data"##`.
David Tolnay360efd22018-01-04 23:35:26 -0800384 ///
385 /// The unsigned integer is the number of `#` symbols used.
386 Raw(usize),
Alex Crichton62a0a592017-05-22 13:58:53 -0700387 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700388}
389
David Tolnay360efd22018-01-04 23:35:26 -0800390ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800391 /// The suffix on an integer literal if any, like the `u8` in `127u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800392 ///
393 /// *This type is available if Syn is built with the `"derive"` or `"full"`
394 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800395 pub enum IntSuffix #no_visit {
396 I8,
397 I16,
398 I32,
399 I64,
400 I128,
401 Isize,
402 U8,
403 U16,
404 U32,
405 U64,
406 U128,
407 Usize,
408 None,
Pascal Hertleif36342c52016-10-19 10:31:42 +0200409 }
410}
411
David Tolnay360efd22018-01-04 23:35:26 -0800412ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800413 /// The suffix on a floating point literal if any, like the `f32` in
414 /// `1.0f32`.
David Tolnay461d98e2018-01-07 11:07:19 -0800415 ///
416 /// *This type is available if Syn is built with the `"derive"` or `"full"`
417 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800418 pub enum FloatSuffix #no_visit {
419 F32,
420 F64,
421 None,
Alex Crichton2e0229c2017-05-23 09:34:50 -0700422 }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800423}
424
425#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400426#[doc(hidden)]
427#[allow(non_snake_case)]
428pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
429 match marker {}
430}
431
432#[cfg(feature = "parsing")]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700433pub mod parsing {
434 use super::*;
David Tolnay4fb71232018-08-25 23:14:50 -0400435 use parse::{Parse, ParseStream, Result};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700436
David Tolnay4fb71232018-08-25 23:14:50 -0400437 impl Parse for Lit {
438 fn parse(input: ParseStream) -> Result<Self> {
439 input.step_cursor(|cursor| {
440 match cursor.literal() {
David Tolnay9e0e8332018-08-30 17:48:48 -0700441 Some((lit, rest)) => Ok((Lit::new(lit), rest)),
David Tolnay4fb71232018-08-25 23:14:50 -0400442 _ => match cursor.ident() {
443 Some((ident, rest)) => Ok((
444 Lit::Bool(LitBool {
445 value: if ident == "true" {
446 true
447 } else if ident == "false" {
448 false
449 } else {
David Tolnaybff5b3a2018-08-30 17:56:25 -0700450 return Err(cursor.error("expected literal"));
David Tolnay4fb71232018-08-25 23:14:50 -0400451 },
452 span: ident.span(),
453 }),
454 rest,
455 )),
David Tolnaybff5b3a2018-08-30 17:56:25 -0700456 _ => Err(cursor.error("expected literal"))
David Tolnay4fb71232018-08-25 23:14:50 -0400457 },
David Tolnay7037c9b2018-01-23 09:34:09 -0800458 }
David Tolnay4fb71232018-08-25 23:14:50 -0400459 })
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800460 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700461 }
David Tolnay360efd22018-01-04 23:35:26 -0800462
David Tolnaya7d69fc2018-08-26 13:30:24 -0400463 impl Parse for LitStr {
464 fn parse(input: ParseStream) -> Result<Self> {
465 let head = input.fork();
466 match input.parse()? {
467 Lit::Str(lit) => Ok(lit),
468 _ => Err(head.error("expected string literal")),
469 }
470 }
471 }
David Tolnay360efd22018-01-04 23:35:26 -0800472
David Tolnaya7d69fc2018-08-26 13:30:24 -0400473 impl Parse for LitByteStr {
474 fn parse(input: ParseStream) -> Result<Self> {
475 let head = input.fork();
476 match input.parse()? {
477 Lit::ByteStr(lit) => Ok(lit),
478 _ => Err(head.error("expected byte string literal")),
479 }
480 }
481 }
David Tolnay360efd22018-01-04 23:35:26 -0800482
David Tolnaya7d69fc2018-08-26 13:30:24 -0400483 impl Parse for LitByte {
484 fn parse(input: ParseStream) -> Result<Self> {
485 let head = input.fork();
486 match input.parse()? {
487 Lit::Byte(lit) => Ok(lit),
488 _ => Err(head.error("expected byte literal")),
489 }
490 }
491 }
David Tolnay360efd22018-01-04 23:35:26 -0800492
David Tolnaya7d69fc2018-08-26 13:30:24 -0400493 impl Parse for LitChar {
494 fn parse(input: ParseStream) -> Result<Self> {
495 let head = input.fork();
496 match input.parse()? {
497 Lit::Char(lit) => Ok(lit),
498 _ => Err(head.error("expected character literal")),
499 }
500 }
501 }
David Tolnay360efd22018-01-04 23:35:26 -0800502
David Tolnaya7d69fc2018-08-26 13:30:24 -0400503 impl Parse for LitInt {
504 fn parse(input: ParseStream) -> Result<Self> {
505 let head = input.fork();
506 match input.parse()? {
507 Lit::Int(lit) => Ok(lit),
508 _ => Err(head.error("expected integer literal")),
509 }
510 }
511 }
David Tolnay360efd22018-01-04 23:35:26 -0800512
David Tolnaya7d69fc2018-08-26 13:30:24 -0400513 impl Parse for LitFloat {
514 fn parse(input: ParseStream) -> Result<Self> {
515 let head = input.fork();
516 match input.parse()? {
517 Lit::Float(lit) => Ok(lit),
518 _ => Err(head.error("expected floating point literal")),
519 }
520 }
521 }
David Tolnay360efd22018-01-04 23:35:26 -0800522
David Tolnaya7d69fc2018-08-26 13:30:24 -0400523 impl Parse for LitBool {
524 fn parse(input: ParseStream) -> Result<Self> {
525 let head = input.fork();
526 match input.parse()? {
527 Lit::Bool(lit) => Ok(lit),
528 _ => Err(head.error("expected boolean literal")),
529 }
530 }
531 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700532}
533
534#[cfg(feature = "printing")]
535mod printing {
536 use super::*;
Alex Crichtona74a1c82018-05-16 10:20:44 -0700537 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700538 use quote::{ToTokens, TokenStreamExt};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700539
David Tolnay360efd22018-01-04 23:35:26 -0800540 impl ToTokens for LitStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700541 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700542 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800543 }
544 }
545
546 impl ToTokens for LitByteStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700547 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700548 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800549 }
550 }
551
552 impl ToTokens for LitByte {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700553 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700554 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800555 }
556 }
557
558 impl ToTokens for LitChar {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700559 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700560 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800561 }
562 }
563
564 impl ToTokens for LitInt {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700565 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700566 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800567 }
568 }
569
570 impl ToTokens for LitFloat {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700571 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700572 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800573 }
574 }
575
576 impl ToTokens for LitBool {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700577 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700578 let s = if self.value { "true" } else { "false" };
Alex Crichtona74a1c82018-05-16 10:20:44 -0700579 tokens.append(Ident::new(s, self.span));
David Tolnay360efd22018-01-04 23:35:26 -0800580 }
581 }
582
583 impl ToTokens for LitVerbatim {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700584 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700585 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800586 }
587 }
588}
589
590mod value {
591 use super::*;
David Tolnay94d2b792018-04-29 12:26:10 -0700592 use proc_macro2::TokenStream;
David Tolnay360efd22018-01-04 23:35:26 -0800593 use std::char;
594 use std::ops::{Index, RangeFrom};
David Tolnay360efd22018-01-04 23:35:26 -0800595
David Tolnay7d1d1282018-01-06 16:10:51 -0800596 impl Lit {
David Tolnay780292d2018-01-22 23:26:44 -0800597 /// Interpret a Syn literal from a proc-macro2 literal.
598 ///
599 /// Not all proc-macro2 literals are valid Syn literals. In particular,
600 /// doc comments are considered by proc-macro2 to be literals but in Syn
601 /// they are [`Attribute`].
602 ///
603 /// [`Attribute`]: struct.Attribute.html
604 ///
605 /// # Panics
606 ///
607 /// Panics if the input is a doc comment literal.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700608 pub fn new(token: Literal) -> Self {
David Tolnay7d1d1282018-01-06 16:10:51 -0800609 let value = token.to_string();
610
611 match value::byte(&value, 0) {
David Tolnay94d2b792018-04-29 12:26:10 -0700612 b'"' | b'r' => return Lit::Str(LitStr { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800613 b'b' => match value::byte(&value, 1) {
David Tolnay94d2b792018-04-29 12:26:10 -0700614 b'"' | b'r' => return Lit::ByteStr(LitByteStr { token: token }),
615 b'\'' => return Lit::Byte(LitByte { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800616 _ => {}
617 },
David Tolnay94d2b792018-04-29 12:26:10 -0700618 b'\'' => return Lit::Char(LitChar { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800619 b'0'...b'9' => if number_is_int(&value) {
David Tolnay94d2b792018-04-29 12:26:10 -0700620 return Lit::Int(LitInt { token: token });
David Tolnay7d1d1282018-01-06 16:10:51 -0800621 } else if number_is_float(&value) {
David Tolnay94d2b792018-04-29 12:26:10 -0700622 return Lit::Float(LitFloat { token: token });
David Tolnay7d1d1282018-01-06 16:10:51 -0800623 } else {
624 // number overflow
David Tolnay94d2b792018-04-29 12:26:10 -0700625 return Lit::Verbatim(LitVerbatim { token: token });
David Tolnay7d1d1282018-01-06 16:10:51 -0800626 },
627 _ => if value == "true" || value == "false" {
628 return Lit::Bool(LitBool {
629 value: value == "true",
Alex Crichton9a4dca22018-03-28 06:32:19 -0700630 span: token.span(),
David Tolnay7d1d1282018-01-06 16:10:51 -0800631 });
632 },
633 }
634
635 panic!("Unrecognized literal: {}", value);
636 }
637 }
638
639 fn number_is_int(value: &str) -> bool {
640 if number_is_float(value) {
641 false
642 } else {
643 value::parse_lit_int(value).is_some()
644 }
645 }
646
647 fn number_is_float(value: &str) -> bool {
648 if value.contains('.') {
649 true
650 } else if value.starts_with("0x") || value.ends_with("size") {
651 false
652 } else {
653 value.contains('e') || value.contains('E')
654 }
655 }
656
David Tolnay360efd22018-01-04 23:35:26 -0800657 /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
658 /// past the end of the input buffer.
659 pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
660 let s = s.as_ref();
661 if idx < s.len() {
662 s[idx]
663 } else {
664 0
665 }
666 }
667
668 fn next_chr(s: &str) -> char {
669 s.chars().next().unwrap_or('\0')
670 }
671
672 pub fn parse_lit_str(s: &str) -> String {
673 match byte(s, 0) {
674 b'"' => parse_lit_str_cooked(s),
675 b'r' => parse_lit_str_raw(s),
676 _ => unreachable!(),
677 }
678 }
679
David Tolnay76ebcdd2018-01-05 17:07:26 -0800680 // Clippy false positive
681 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
682 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800683 fn parse_lit_str_cooked(mut s: &str) -> String {
684 assert_eq!(byte(s, 0), b'"');
685 s = &s[1..];
686
687 let mut out = String::new();
688 'outer: loop {
689 let ch = match byte(s, 0) {
690 b'"' => break,
691 b'\\' => {
692 let b = byte(s, 1);
693 s = &s[2..];
694 match b {
695 b'x' => {
696 let (byte, rest) = backslash_x(s);
697 s = rest;
698 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800699 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800700 }
701 b'u' => {
David Tolnay76ebcdd2018-01-05 17:07:26 -0800702 let (chr, rest) = backslash_u(s);
David Tolnay360efd22018-01-04 23:35:26 -0800703 s = rest;
704 chr
705 }
706 b'n' => '\n',
707 b'r' => '\r',
708 b't' => '\t',
709 b'\\' => '\\',
710 b'0' => '\0',
711 b'\'' => '\'',
712 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800713 b'\r' | b'\n' => loop {
714 let ch = next_chr(s);
715 if ch.is_whitespace() {
716 s = &s[ch.len_utf8()..];
717 } else {
718 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800719 }
David Tolnay61037c62018-01-05 16:21:03 -0800720 },
721 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800722 }
723 }
724 b'\r' => {
725 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
726 s = &s[2..];
727 '\n'
728 }
729 _ => {
730 let ch = next_chr(s);
731 s = &s[ch.len_utf8()..];
732 ch
733 }
734 };
735 out.push(ch);
736 }
737
738 assert_eq!(s, "\"");
739 out
740 }
741
742 fn parse_lit_str_raw(mut s: &str) -> String {
743 assert_eq!(byte(s, 0), b'r');
744 s = &s[1..];
745
746 let mut pounds = 0;
747 while byte(s, pounds) == b'#' {
748 pounds += 1;
749 }
750 assert_eq!(byte(s, pounds), b'"');
751 assert_eq!(byte(s, s.len() - pounds - 1), b'"');
752 for end in s[s.len() - pounds..].bytes() {
753 assert_eq!(end, b'#');
754 }
755
756 s[pounds + 1..s.len() - pounds - 1].to_owned()
757 }
758
759 pub fn parse_lit_byte_str(s: &str) -> Vec<u8> {
760 assert_eq!(byte(s, 0), b'b');
761 match byte(s, 1) {
762 b'"' => parse_lit_byte_str_cooked(s),
763 b'r' => parse_lit_byte_str_raw(s),
764 _ => unreachable!(),
765 }
766 }
767
David Tolnay76ebcdd2018-01-05 17:07:26 -0800768 // Clippy false positive
769 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
770 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800771 fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> {
772 assert_eq!(byte(s, 0), b'b');
773 assert_eq!(byte(s, 1), b'"');
774 s = &s[2..];
775
776 // We're going to want to have slices which don't respect codepoint boundaries.
777 let mut s = s.as_bytes();
778
779 let mut out = Vec::new();
780 'outer: loop {
781 let byte = match byte(s, 0) {
782 b'"' => break,
783 b'\\' => {
784 let b = byte(s, 1);
785 s = &s[2..];
786 match b {
787 b'x' => {
788 let (b, rest) = backslash_x(s);
789 s = rest;
790 b
791 }
792 b'n' => b'\n',
793 b'r' => b'\r',
794 b't' => b'\t',
795 b'\\' => b'\\',
796 b'0' => b'\0',
797 b'\'' => b'\'',
798 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800799 b'\r' | b'\n' => loop {
800 let byte = byte(s, 0);
David Tolnay76ebcdd2018-01-05 17:07:26 -0800801 let ch = char::from_u32(u32::from(byte)).unwrap();
David Tolnay61037c62018-01-05 16:21:03 -0800802 if ch.is_whitespace() {
803 s = &s[1..];
804 } else {
805 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800806 }
David Tolnay61037c62018-01-05 16:21:03 -0800807 },
808 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800809 }
810 }
811 b'\r' => {
812 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
813 s = &s[2..];
814 b'\n'
815 }
816 b => {
817 s = &s[1..];
818 b
819 }
820 };
821 out.push(byte);
822 }
823
824 assert_eq!(s, b"\"");
825 out
826 }
827
828 fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> {
829 assert_eq!(byte(s, 0), b'b');
830 parse_lit_str_raw(&s[1..]).into_bytes()
831 }
832
833 pub fn parse_lit_byte(s: &str) -> u8 {
834 assert_eq!(byte(s, 0), b'b');
835 assert_eq!(byte(s, 1), b'\'');
836
837 // We're going to want to have slices which don't respect codepoint boundaries.
838 let mut s = s[2..].as_bytes();
839
840 let b = match byte(s, 0) {
841 b'\\' => {
842 let b = byte(s, 1);
843 s = &s[2..];
844 match b {
845 b'x' => {
846 let (b, rest) = backslash_x(s);
847 s = rest;
848 b
849 }
850 b'n' => b'\n',
851 b'r' => b'\r',
852 b't' => b'\t',
853 b'\\' => b'\\',
854 b'0' => b'\0',
855 b'\'' => b'\'',
856 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800857 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800858 }
859 }
860 b => {
861 s = &s[1..];
862 b
863 }
864 };
865
866 assert_eq!(byte(s, 0), b'\'');
867 b
868 }
869
870 pub fn parse_lit_char(mut s: &str) -> char {
871 assert_eq!(byte(s, 0), b'\'');
872 s = &s[1..];
873
874 let ch = match byte(s, 0) {
875 b'\\' => {
876 let b = byte(s, 1);
877 s = &s[2..];
878 match b {
879 b'x' => {
880 let (byte, rest) = backslash_x(s);
881 s = rest;
882 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800883 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800884 }
885 b'u' => {
886 let (chr, rest) = backslash_u(s);
887 s = rest;
888 chr
889 }
890 b'n' => '\n',
891 b'r' => '\r',
892 b't' => '\t',
893 b'\\' => '\\',
894 b'0' => '\0',
895 b'\'' => '\'',
896 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800897 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800898 }
899 }
900 _ => {
901 let ch = next_chr(s);
902 s = &s[ch.len_utf8()..];
903 ch
904 }
905 };
906 assert_eq!(s, "\'", "Expected end of char literal");
907 ch
908 }
909
910 fn backslash_x<S>(s: &S) -> (u8, &S)
David Tolnay61037c62018-01-05 16:21:03 -0800911 where
912 S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
David Tolnay360efd22018-01-04 23:35:26 -0800913 {
914 let mut ch = 0;
915 let b0 = byte(s, 0);
916 let b1 = byte(s, 1);
917 ch += 0x10 * match b0 {
918 b'0'...b'9' => b0 - b'0',
919 b'a'...b'f' => 10 + (b0 - b'a'),
920 b'A'...b'F' => 10 + (b0 - b'A'),
921 _ => panic!("unexpected non-hex character after \\x"),
922 };
David Tolnay76ebcdd2018-01-05 17:07:26 -0800923 ch += match b1 {
David Tolnay360efd22018-01-04 23:35:26 -0800924 b'0'...b'9' => b1 - b'0',
925 b'a'...b'f' => 10 + (b1 - b'a'),
926 b'A'...b'F' => 10 + (b1 - b'A'),
927 _ => panic!("unexpected non-hex character after \\x"),
928 };
929 (ch, &s[2..])
930 }
931
932 fn backslash_u(mut s: &str) -> (char, &str) {
933 if byte(s, 0) != b'{' {
934 panic!("expected {{ after \\u");
935 }
936 s = &s[1..];
937
938 let mut ch = 0;
939 for _ in 0..6 {
940 let b = byte(s, 0);
941 match b {
942 b'0'...b'9' => {
943 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800944 ch += u32::from(b - b'0');
David Tolnay360efd22018-01-04 23:35:26 -0800945 s = &s[1..];
946 }
947 b'a'...b'f' => {
948 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800949 ch += u32::from(10 + b - b'a');
David Tolnay360efd22018-01-04 23:35:26 -0800950 s = &s[1..];
951 }
952 b'A'...b'F' => {
953 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800954 ch += u32::from(10 + b - b'A');
David Tolnay360efd22018-01-04 23:35:26 -0800955 s = &s[1..];
956 }
957 b'}' => break,
958 _ => panic!("unexpected non-hex character after \\u"),
959 }
960 }
961 assert!(byte(s, 0) == b'}');
962 s = &s[1..];
963
964 if let Some(ch) = char::from_u32(ch) {
965 (ch, s)
966 } else {
967 panic!("character code {:x} is not a valid unicode character", ch);
968 }
969 }
970
971 pub fn parse_lit_int(mut s: &str) -> Option<u64> {
972 let base = match (byte(s, 0), byte(s, 1)) {
973 (b'0', b'x') => {
974 s = &s[2..];
975 16
976 }
977 (b'0', b'o') => {
978 s = &s[2..];
979 8
980 }
981 (b'0', b'b') => {
982 s = &s[2..];
983 2
984 }
985 (b'0'...b'9', _) => 10,
986 _ => unreachable!(),
987 };
988
989 let mut value = 0u64;
990 loop {
991 let b = byte(s, 0);
992 let digit = match b {
David Tolnay76ebcdd2018-01-05 17:07:26 -0800993 b'0'...b'9' => u64::from(b - b'0'),
994 b'a'...b'f' if base > 10 => 10 + u64::from(b - b'a'),
995 b'A'...b'F' if base > 10 => 10 + u64::from(b - b'A'),
David Tolnay360efd22018-01-04 23:35:26 -0800996 b'_' => {
997 s = &s[1..];
998 continue;
999 }
1000 // NOTE: Looking at a floating point literal, we don't want to
1001 // consider these integers.
1002 b'.' if base == 10 => return None,
1003 b'e' | b'E' if base == 10 => return None,
1004 _ => break,
1005 };
1006
1007 if digit >= base {
1008 panic!("Unexpected digit {:x} out of base range", digit);
1009 }
1010
1011 value = match value.checked_mul(base) {
1012 Some(value) => value,
1013 None => return None,
1014 };
1015 value = match value.checked_add(digit) {
1016 Some(value) => value,
1017 None => return None,
1018 };
1019 s = &s[1..];
1020 }
1021
1022 Some(value)
1023 }
1024
1025 pub fn parse_lit_float(input: &str) -> f64 {
1026 // Rust's floating point literals are very similar to the ones parsed by
1027 // the standard library, except that rust's literals can contain
1028 // ignorable underscores. Let's remove those underscores.
1029 let mut bytes = input.to_owned().into_bytes();
1030 let mut write = 0;
1031 for read in 0..bytes.len() {
1032 if bytes[read] == b'_' {
1033 continue; // Don't increase write
David Tolnay76ebcdd2018-01-05 17:07:26 -08001034 }
1035 if write != read {
David Tolnay360efd22018-01-04 23:35:26 -08001036 let x = bytes[read];
1037 bytes[write] = x;
1038 }
1039 write += 1;
1040 }
1041 bytes.truncate(write);
1042 let input = String::from_utf8(bytes).unwrap();
David Tolnay76ebcdd2018-01-05 17:07:26 -08001043 let end = input.find('f').unwrap_or_else(|| input.len());
David Tolnay360efd22018-01-04 23:35:26 -08001044 input[..end].parse().unwrap()
1045 }
1046
1047 pub fn to_literal(s: &str) -> Literal {
1048 let stream = s.parse::<TokenStream>().unwrap();
Alex Crichton9a4dca22018-03-28 06:32:19 -07001049 match stream.into_iter().next().unwrap() {
1050 TokenTree::Literal(l) => l,
David Tolnay360efd22018-01-04 23:35:26 -08001051 _ => unreachable!(),
David Tolnayf17fd2f2016-10-07 23:38:08 -07001052 }
1053 }
David Tolnayf4bbbd92016-09-23 14:41:55 -07001054}