blob: 5b2bf86cc6843714768967373f12c1b5e8a57afb [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 Tolnayad4b2472018-08-25 08:25:24 -040018use {Error, Synom};
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;
27
David Tolnay360efd22018-01-04 23:35:26 -080028ast_enum_of_structs! {
David Tolnayabf5c2e2018-01-06 23:30:04 -080029 /// A Rust literal such as a string or integer or boolean.
David Tolnay614a0142018-01-07 10:25:43 -080030 ///
David Tolnay461d98e2018-01-07 11:07:19 -080031 /// *This type is available if Syn is built with the `"derive"` or `"full"`
32 /// feature.*
33 ///
David Tolnay614a0142018-01-07 10:25:43 -080034 /// # Syntax tree enum
35 ///
36 /// This type is a [syntax tree enum].
37 ///
38 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
David Tolnay360efd22018-01-04 23:35:26 -080039 pub enum Lit {
David Tolnayabf5c2e2018-01-06 23:30:04 -080040 /// A UTF-8 string literal: `"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 Str(LitStr #manual_extra_traits {
45 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080046 }),
Alex Crichtonccbb45d2017-05-23 10:58:24 -070047
David Tolnayabf5c2e2018-01-06 23:30:04 -080048 /// A byte string literal: `b"foo"`.
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 ByteStr(LitByteStr #manual_extra_traits {
53 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080054 }),
55
David Tolnayabf5c2e2018-01-06 23:30:04 -080056 /// A byte literal: `b'f'`.
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 Byte(LitByte #manual_extra_traits {
61 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080062 }),
63
David Tolnayabf5c2e2018-01-06 23:30:04 -080064 /// A character literal: `'a'`.
David Tolnay461d98e2018-01-07 11:07:19 -080065 ///
66 /// *This type is available if Syn is built with the `"derive"` or
67 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080068 pub Char(LitChar #manual_extra_traits {
69 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080070 }),
71
David Tolnayabf5c2e2018-01-06 23:30:04 -080072 /// An integer literal: `1` or `1u16`.
David Tolnay360efd22018-01-04 23:35:26 -080073 ///
74 /// Holds up to 64 bits of data. Use `LitVerbatim` for any larger
75 /// integer literal.
David Tolnay461d98e2018-01-07 11:07:19 -080076 ///
77 /// *This type is available if Syn is built with the `"derive"` or
78 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080079 pub Int(LitInt #manual_extra_traits {
80 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080081 }),
82
David Tolnayabf5c2e2018-01-06 23:30:04 -080083 /// A floating point literal: `1f64` or `1.0e10f64`.
David Tolnay360efd22018-01-04 23:35:26 -080084 ///
85 /// Must be finite. May not be infinte or NaN.
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 Float(LitFloat #manual_extra_traits {
90 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080091 }),
92
David Tolnayabf5c2e2018-01-06 23:30:04 -080093 /// A boolean literal: `true` or `false`.
David Tolnay461d98e2018-01-07 11:07:19 -080094 ///
95 /// *This type is available if Syn is built with the `"derive"` or
96 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080097 pub Bool(LitBool #manual_extra_traits {
98 pub value: bool,
99 pub span: Span,
100 }),
101
David Tolnayabf5c2e2018-01-06 23:30:04 -0800102 /// A raw token literal not interpreted by Syn, possibly because it
103 /// represents an integer larger than 64 bits.
David Tolnay461d98e2018-01-07 11:07:19 -0800104 ///
105 /// *This type is available if Syn is built with the `"derive"` or
106 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800107 pub Verbatim(LitVerbatim #manual_extra_traits {
108 pub token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -0800109 }),
110 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700111}
112
David Tolnay360efd22018-01-04 23:35:26 -0800113impl LitStr {
114 pub fn new(value: &str, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700115 let mut lit = Literal::string(value);
116 lit.set_span(span);
David Tolnay94d2b792018-04-29 12:26:10 -0700117 LitStr { token: lit }
David Tolnay360efd22018-01-04 23:35:26 -0800118 }
119
120 pub fn value(&self) -> String {
121 value::parse_lit_str(&self.token.to_string())
122 }
David Tolnayd53ac2b2018-01-27 19:00:06 -0800123
124 /// Parse a syntax tree node from the content of this string literal.
125 ///
126 /// All spans in the syntax tree will point to the span of this `LitStr`.
127 #[cfg(feature = "parsing")]
David Tolnayad4b2472018-08-25 08:25:24 -0400128 pub fn parse<T: Synom>(&self) -> Result<T, Error> {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700129 use proc_macro2::Group;
130
David Tolnayd53ac2b2018-01-27 19:00:06 -0800131 // Parse string literal into a token stream with every span equal to the
132 // original literal's span.
David Tolnayad4b2472018-08-25 08:25:24 -0400133 fn spanned_tokens(s: &LitStr) -> Result<TokenStream, Error> {
David Tolnayd53ac2b2018-01-27 19:00:06 -0800134 let stream = ::parse_str(&s.value())?;
Alex Crichton9a4dca22018-03-28 06:32:19 -0700135 Ok(respan_token_stream(stream, s.span()))
David Tolnayd53ac2b2018-01-27 19:00:06 -0800136 }
137
138 // Token stream with every span replaced by the given one.
139 fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
David Tolnay94d2b792018-04-29 12:26:10 -0700140 stream
141 .into_iter()
142 .map(|token| respan_token_tree(token, span))
143 .collect()
David Tolnayd53ac2b2018-01-27 19:00:06 -0800144 }
145
146 // Token tree with every span replaced by the given one.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700147 fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
148 match token {
149 TokenTree::Group(ref mut g) => {
150 let stream = respan_token_stream(g.stream().clone(), span);
151 *g = Group::new(g.delimiter(), stream);
152 g.set_span(span);
153 }
154 ref mut other => other.set_span(span),
David Tolnayd53ac2b2018-01-27 19:00:06 -0800155 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700156 token
David Tolnayd53ac2b2018-01-27 19:00:06 -0800157 }
158
159 spanned_tokens(self).and_then(::parse2)
160 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700161
162 pub fn span(&self) -> Span {
163 self.token.span()
164 }
165
166 pub fn set_span(&mut self, span: Span) {
167 self.token.set_span(span)
168 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700169}
170
David Tolnay360efd22018-01-04 23:35:26 -0800171impl LitByteStr {
172 pub fn new(value: &[u8], span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700173 let mut token = Literal::byte_string(value);
174 token.set_span(span);
175 LitByteStr { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800176 }
177
178 pub fn value(&self) -> Vec<u8> {
179 value::parse_lit_byte_str(&self.token.to_string())
180 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700181
182 pub fn span(&self) -> Span {
183 self.token.span()
184 }
185
186 pub fn set_span(&mut self, span: Span) {
187 self.token.set_span(span)
188 }
David Tolnay360efd22018-01-04 23:35:26 -0800189}
190
191impl LitByte {
192 pub fn new(value: u8, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700193 let mut token = Literal::u8_suffixed(value);
194 token.set_span(span);
195 LitByte { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800196 }
197
198 pub fn value(&self) -> u8 {
199 value::parse_lit_byte(&self.token.to_string())
200 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700201
202 pub fn span(&self) -> Span {
203 self.token.span()
204 }
205
206 pub fn set_span(&mut self, span: Span) {
207 self.token.set_span(span)
208 }
David Tolnay360efd22018-01-04 23:35:26 -0800209}
210
211impl LitChar {
212 pub fn new(value: char, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700213 let mut token = Literal::character(value);
214 token.set_span(span);
215 LitChar { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800216 }
217
218 pub fn value(&self) -> char {
219 value::parse_lit_char(&self.token.to_string())
220 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700221
222 pub fn span(&self) -> Span {
223 self.token.span()
224 }
225
226 pub fn set_span(&mut self, span: Span) {
227 self.token.set_span(span)
228 }
David Tolnay360efd22018-01-04 23:35:26 -0800229}
230
231impl LitInt {
232 pub fn new(value: u64, suffix: IntSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700233 let mut token = match suffix {
234 IntSuffix::Isize => Literal::isize_suffixed(value as isize),
235 IntSuffix::I8 => Literal::i8_suffixed(value as i8),
236 IntSuffix::I16 => Literal::i16_suffixed(value as i16),
237 IntSuffix::I32 => Literal::i32_suffixed(value as i32),
238 IntSuffix::I64 => Literal::i64_suffixed(value as i64),
239 IntSuffix::I128 => value::to_literal(&format!("{}i128", value)),
240 IntSuffix::Usize => Literal::usize_suffixed(value as usize),
241 IntSuffix::U8 => Literal::u8_suffixed(value as u8),
242 IntSuffix::U16 => Literal::u16_suffixed(value as u16),
243 IntSuffix::U32 => Literal::u32_suffixed(value as u32),
244 IntSuffix::U64 => Literal::u64_suffixed(value),
245 IntSuffix::U128 => value::to_literal(&format!("{}u128", value)),
246 IntSuffix::None => Literal::u64_unsuffixed(value),
247 };
248 token.set_span(span);
249 LitInt { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800250 }
251
252 pub fn value(&self) -> u64 {
253 value::parse_lit_int(&self.token.to_string()).unwrap()
254 }
255
256 pub fn suffix(&self) -> IntSuffix {
257 let value = self.token.to_string();
258 for (s, suffix) in vec![
259 ("i8", IntSuffix::I8),
260 ("i16", IntSuffix::I16),
261 ("i32", IntSuffix::I32),
262 ("i64", IntSuffix::I64),
263 ("i128", IntSuffix::I128),
264 ("isize", IntSuffix::Isize),
265 ("u8", IntSuffix::U8),
266 ("u16", IntSuffix::U16),
267 ("u32", IntSuffix::U32),
268 ("u64", IntSuffix::U64),
269 ("u128", IntSuffix::U128),
270 ("usize", IntSuffix::Usize),
271 ] {
272 if value.ends_with(s) {
273 return suffix;
274 }
275 }
276 IntSuffix::None
277 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700278
279 pub fn span(&self) -> Span {
280 self.token.span()
281 }
282
283 pub fn set_span(&mut self, span: Span) {
284 self.token.set_span(span)
285 }
David Tolnay360efd22018-01-04 23:35:26 -0800286}
287
288impl LitFloat {
289 pub fn new(value: f64, suffix: FloatSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700290 let mut token = match suffix {
291 FloatSuffix::F32 => Literal::f32_suffixed(value as f32),
292 FloatSuffix::F64 => Literal::f64_suffixed(value),
293 FloatSuffix::None => Literal::f64_unsuffixed(value),
294 };
295 token.set_span(span);
296 LitFloat { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800297 }
298
299 pub fn value(&self) -> f64 {
300 value::parse_lit_float(&self.token.to_string())
301 }
302
303 pub fn suffix(&self) -> FloatSuffix {
304 let value = self.token.to_string();
David Tolnay61037c62018-01-05 16:21:03 -0800305 for (s, suffix) in vec![("f32", FloatSuffix::F32), ("f64", FloatSuffix::F64)] {
David Tolnay360efd22018-01-04 23:35:26 -0800306 if value.ends_with(s) {
307 return suffix;
308 }
309 }
310 FloatSuffix::None
311 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700312
313 pub fn span(&self) -> Span {
314 self.token.span()
315 }
316
317 pub fn set_span(&mut self, span: Span) {
318 self.token.set_span(span)
319 }
David Tolnay360efd22018-01-04 23:35:26 -0800320}
321
322macro_rules! lit_extra_traits {
323 ($ty:ident, $field:ident) => {
324 #[cfg(feature = "extra-traits")]
325 impl Eq for $ty {}
326
327 #[cfg(feature = "extra-traits")]
328 impl PartialEq for $ty {
329 fn eq(&self, other: &Self) -> bool {
330 self.$field.to_string() == other.$field.to_string()
331 }
332 }
333
334 #[cfg(feature = "extra-traits")]
335 impl Hash for $ty {
336 fn hash<H>(&self, state: &mut H)
337 where
338 H: Hasher,
339 {
340 self.$field.to_string().hash(state);
341 }
David Tolnay9c76bcb2017-12-26 23:14:59 -0500342 }
David Tolnay6a170ce2018-08-26 22:29:24 -0700343
344 #[cfg(feature = "parsing")]
345 #[doc(hidden)]
346 #[allow(non_snake_case)]
347 pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
348 match marker {}
349 }
David Tolnay94d2b792018-04-29 12:26:10 -0700350 };
David Tolnayf4bbbd92016-09-23 14:41:55 -0700351}
352
Alex Crichton9a4dca22018-03-28 06:32:19 -0700353impl LitVerbatim {
354 pub fn span(&self) -> Span {
355 self.token.span()
356 }
357
358 pub fn set_span(&mut self, span: Span) {
359 self.token.set_span(span)
360 }
361}
362
David Tolnay360efd22018-01-04 23:35:26 -0800363lit_extra_traits!(LitStr, token);
364lit_extra_traits!(LitByteStr, token);
365lit_extra_traits!(LitByte, token);
366lit_extra_traits!(LitChar, token);
367lit_extra_traits!(LitInt, token);
368lit_extra_traits!(LitFloat, token);
369lit_extra_traits!(LitBool, value);
370lit_extra_traits!(LitVerbatim, token);
371
372ast_enum! {
David Tolnay05658502018-01-07 09:56:37 -0800373 /// The style of a string literal, either plain quoted or a raw string like
David Tolnayabf5c2e2018-01-06 23:30:04 -0800374 /// `r##"data"##`.
David Tolnay461d98e2018-01-07 11:07:19 -0800375 ///
376 /// *This type is available if Syn is built with the `"derive"` or `"full"`
377 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800378 pub enum StrStyle #no_visit {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800379 /// An ordinary string like `"data"`.
David Tolnay360efd22018-01-04 23:35:26 -0800380 Cooked,
David Tolnayabf5c2e2018-01-06 23:30:04 -0800381 /// A raw string like `r##"data"##`.
David Tolnay360efd22018-01-04 23:35:26 -0800382 ///
383 /// The unsigned integer is the number of `#` symbols used.
384 Raw(usize),
Alex Crichton62a0a592017-05-22 13:58:53 -0700385 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700386}
387
David Tolnay360efd22018-01-04 23:35:26 -0800388ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800389 /// The suffix on an integer literal if any, like the `u8` in `127u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800390 ///
391 /// *This type is available if Syn is built with the `"derive"` or `"full"`
392 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800393 pub enum IntSuffix #no_visit {
394 I8,
395 I16,
396 I32,
397 I64,
398 I128,
399 Isize,
400 U8,
401 U16,
402 U32,
403 U64,
404 U128,
405 Usize,
406 None,
Pascal Hertleif36342c52016-10-19 10:31:42 +0200407 }
408}
409
David Tolnay360efd22018-01-04 23:35:26 -0800410ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800411 /// The suffix on a floating point literal if any, like the `f32` in
412 /// `1.0f32`.
David Tolnay461d98e2018-01-07 11:07:19 -0800413 ///
414 /// *This type is available if Syn is built with the `"derive"` or `"full"`
415 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800416 pub enum FloatSuffix #no_visit {
417 F32,
418 F64,
419 None,
Alex Crichton2e0229c2017-05-23 09:34:50 -0700420 }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800421}
422
423#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400424#[doc(hidden)]
425#[allow(non_snake_case)]
426pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
427 match marker {}
428}
429
430#[cfg(feature = "parsing")]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700431pub mod parsing {
432 use super::*;
David Tolnay4fb71232018-08-25 23:14:50 -0400433 use parse::{Parse, ParseStream, Result};
David Tolnay203557a2017-12-27 23:59:33 -0500434 use parse_error;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700435
David Tolnay4fb71232018-08-25 23:14:50 -0400436 impl Parse for Lit {
437 fn parse(input: ParseStream) -> Result<Self> {
438 input.step_cursor(|cursor| {
439 match cursor.literal() {
440 Some((lit, rest)) => {
441 if lit.to_string().starts_with('/') {
442 // Doc comment literal which is not a Syn literal
443 parse_error()
444 } else {
445 Ok((Lit::new(lit), rest))
446 }
David Tolnay7037c9b2018-01-23 09:34:09 -0800447 }
David Tolnay4fb71232018-08-25 23:14:50 -0400448 _ => match cursor.ident() {
449 Some((ident, rest)) => Ok((
450 Lit::Bool(LitBool {
451 value: if ident == "true" {
452 true
453 } else if ident == "false" {
454 false
455 } else {
456 return parse_error();
457 },
458 span: ident.span(),
459 }),
460 rest,
461 )),
462 _ => parse_error(),
463 },
David Tolnay7037c9b2018-01-23 09:34:09 -0800464 }
David Tolnay4fb71232018-08-25 23:14:50 -0400465 })
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800466 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700467 }
David Tolnay360efd22018-01-04 23:35:26 -0800468
David Tolnaya7d69fc2018-08-26 13:30:24 -0400469 impl Parse for LitStr {
470 fn parse(input: ParseStream) -> Result<Self> {
471 let head = input.fork();
472 match input.parse()? {
473 Lit::Str(lit) => Ok(lit),
474 _ => Err(head.error("expected string literal")),
475 }
476 }
477 }
David Tolnay360efd22018-01-04 23:35:26 -0800478
David Tolnaya7d69fc2018-08-26 13:30:24 -0400479 impl Parse for LitByteStr {
480 fn parse(input: ParseStream) -> Result<Self> {
481 let head = input.fork();
482 match input.parse()? {
483 Lit::ByteStr(lit) => Ok(lit),
484 _ => Err(head.error("expected byte string literal")),
485 }
486 }
487 }
David Tolnay360efd22018-01-04 23:35:26 -0800488
David Tolnaya7d69fc2018-08-26 13:30:24 -0400489 impl Parse for LitByte {
490 fn parse(input: ParseStream) -> Result<Self> {
491 let head = input.fork();
492 match input.parse()? {
493 Lit::Byte(lit) => Ok(lit),
494 _ => Err(head.error("expected byte literal")),
495 }
496 }
497 }
David Tolnay360efd22018-01-04 23:35:26 -0800498
David Tolnaya7d69fc2018-08-26 13:30:24 -0400499 impl Parse for LitChar {
500 fn parse(input: ParseStream) -> Result<Self> {
501 let head = input.fork();
502 match input.parse()? {
503 Lit::Char(lit) => Ok(lit),
504 _ => Err(head.error("expected character literal")),
505 }
506 }
507 }
David Tolnay360efd22018-01-04 23:35:26 -0800508
David Tolnaya7d69fc2018-08-26 13:30:24 -0400509 impl Parse for LitInt {
510 fn parse(input: ParseStream) -> Result<Self> {
511 let head = input.fork();
512 match input.parse()? {
513 Lit::Int(lit) => Ok(lit),
514 _ => Err(head.error("expected integer literal")),
515 }
516 }
517 }
David Tolnay360efd22018-01-04 23:35:26 -0800518
David Tolnaya7d69fc2018-08-26 13:30:24 -0400519 impl Parse for LitFloat {
520 fn parse(input: ParseStream) -> Result<Self> {
521 let head = input.fork();
522 match input.parse()? {
523 Lit::Float(lit) => Ok(lit),
524 _ => Err(head.error("expected floating point literal")),
525 }
526 }
527 }
David Tolnay360efd22018-01-04 23:35:26 -0800528
David Tolnaya7d69fc2018-08-26 13:30:24 -0400529 impl Parse for LitBool {
530 fn parse(input: ParseStream) -> Result<Self> {
531 let head = input.fork();
532 match input.parse()? {
533 Lit::Bool(lit) => Ok(lit),
534 _ => Err(head.error("expected boolean literal")),
535 }
536 }
537 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700538}
539
540#[cfg(feature = "printing")]
541mod printing {
542 use super::*;
Alex Crichtona74a1c82018-05-16 10:20:44 -0700543 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700544 use quote::{ToTokens, TokenStreamExt};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700545
David Tolnay360efd22018-01-04 23:35:26 -0800546 impl ToTokens for LitStr {
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 LitByteStr {
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 LitByte {
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 LitChar {
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 LitInt {
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 LitFloat {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700577 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700578 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800579 }
580 }
581
582 impl ToTokens for LitBool {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700583 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700584 let s = if self.value { "true" } else { "false" };
Alex Crichtona74a1c82018-05-16 10:20:44 -0700585 tokens.append(Ident::new(s, self.span));
David Tolnay360efd22018-01-04 23:35:26 -0800586 }
587 }
588
589 impl ToTokens for LitVerbatim {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700590 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700591 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800592 }
593 }
594}
595
596mod value {
597 use super::*;
David Tolnay94d2b792018-04-29 12:26:10 -0700598 use proc_macro2::TokenStream;
David Tolnay360efd22018-01-04 23:35:26 -0800599 use std::char;
600 use std::ops::{Index, RangeFrom};
David Tolnay360efd22018-01-04 23:35:26 -0800601
David Tolnay7d1d1282018-01-06 16:10:51 -0800602 impl Lit {
David Tolnay780292d2018-01-22 23:26:44 -0800603 /// Interpret a Syn literal from a proc-macro2 literal.
604 ///
605 /// Not all proc-macro2 literals are valid Syn literals. In particular,
606 /// doc comments are considered by proc-macro2 to be literals but in Syn
607 /// they are [`Attribute`].
608 ///
609 /// [`Attribute`]: struct.Attribute.html
610 ///
611 /// # Panics
612 ///
613 /// Panics if the input is a doc comment literal.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700614 pub fn new(token: Literal) -> Self {
David Tolnay7d1d1282018-01-06 16:10:51 -0800615 let value = token.to_string();
616
617 match value::byte(&value, 0) {
David Tolnay94d2b792018-04-29 12:26:10 -0700618 b'"' | b'r' => return Lit::Str(LitStr { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800619 b'b' => match value::byte(&value, 1) {
David Tolnay94d2b792018-04-29 12:26:10 -0700620 b'"' | b'r' => return Lit::ByteStr(LitByteStr { token: token }),
621 b'\'' => return Lit::Byte(LitByte { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800622 _ => {}
623 },
David Tolnay94d2b792018-04-29 12:26:10 -0700624 b'\'' => return Lit::Char(LitChar { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800625 b'0'...b'9' => if number_is_int(&value) {
David Tolnay94d2b792018-04-29 12:26:10 -0700626 return Lit::Int(LitInt { token: token });
David Tolnay7d1d1282018-01-06 16:10:51 -0800627 } else if number_is_float(&value) {
David Tolnay94d2b792018-04-29 12:26:10 -0700628 return Lit::Float(LitFloat { token: token });
David Tolnay7d1d1282018-01-06 16:10:51 -0800629 } else {
630 // number overflow
David Tolnay94d2b792018-04-29 12:26:10 -0700631 return Lit::Verbatim(LitVerbatim { token: token });
David Tolnay7d1d1282018-01-06 16:10:51 -0800632 },
633 _ => if value == "true" || value == "false" {
634 return Lit::Bool(LitBool {
635 value: value == "true",
Alex Crichton9a4dca22018-03-28 06:32:19 -0700636 span: token.span(),
David Tolnay7d1d1282018-01-06 16:10:51 -0800637 });
638 },
639 }
640
641 panic!("Unrecognized literal: {}", value);
642 }
643 }
644
645 fn number_is_int(value: &str) -> bool {
646 if number_is_float(value) {
647 false
648 } else {
649 value::parse_lit_int(value).is_some()
650 }
651 }
652
653 fn number_is_float(value: &str) -> bool {
654 if value.contains('.') {
655 true
656 } else if value.starts_with("0x") || value.ends_with("size") {
657 false
658 } else {
659 value.contains('e') || value.contains('E')
660 }
661 }
662
David Tolnay360efd22018-01-04 23:35:26 -0800663 /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
664 /// past the end of the input buffer.
665 pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
666 let s = s.as_ref();
667 if idx < s.len() {
668 s[idx]
669 } else {
670 0
671 }
672 }
673
674 fn next_chr(s: &str) -> char {
675 s.chars().next().unwrap_or('\0')
676 }
677
678 pub fn parse_lit_str(s: &str) -> String {
679 match byte(s, 0) {
680 b'"' => parse_lit_str_cooked(s),
681 b'r' => parse_lit_str_raw(s),
682 _ => unreachable!(),
683 }
684 }
685
David Tolnay76ebcdd2018-01-05 17:07:26 -0800686 // Clippy false positive
687 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
688 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800689 fn parse_lit_str_cooked(mut s: &str) -> String {
690 assert_eq!(byte(s, 0), b'"');
691 s = &s[1..];
692
693 let mut out = String::new();
694 'outer: loop {
695 let ch = match byte(s, 0) {
696 b'"' => break,
697 b'\\' => {
698 let b = byte(s, 1);
699 s = &s[2..];
700 match b {
701 b'x' => {
702 let (byte, rest) = backslash_x(s);
703 s = rest;
704 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800705 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800706 }
707 b'u' => {
David Tolnay76ebcdd2018-01-05 17:07:26 -0800708 let (chr, rest) = backslash_u(s);
David Tolnay360efd22018-01-04 23:35:26 -0800709 s = rest;
710 chr
711 }
712 b'n' => '\n',
713 b'r' => '\r',
714 b't' => '\t',
715 b'\\' => '\\',
716 b'0' => '\0',
717 b'\'' => '\'',
718 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800719 b'\r' | b'\n' => loop {
720 let ch = next_chr(s);
721 if ch.is_whitespace() {
722 s = &s[ch.len_utf8()..];
723 } else {
724 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800725 }
David Tolnay61037c62018-01-05 16:21:03 -0800726 },
727 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800728 }
729 }
730 b'\r' => {
731 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
732 s = &s[2..];
733 '\n'
734 }
735 _ => {
736 let ch = next_chr(s);
737 s = &s[ch.len_utf8()..];
738 ch
739 }
740 };
741 out.push(ch);
742 }
743
744 assert_eq!(s, "\"");
745 out
746 }
747
748 fn parse_lit_str_raw(mut s: &str) -> String {
749 assert_eq!(byte(s, 0), b'r');
750 s = &s[1..];
751
752 let mut pounds = 0;
753 while byte(s, pounds) == b'#' {
754 pounds += 1;
755 }
756 assert_eq!(byte(s, pounds), b'"');
757 assert_eq!(byte(s, s.len() - pounds - 1), b'"');
758 for end in s[s.len() - pounds..].bytes() {
759 assert_eq!(end, b'#');
760 }
761
762 s[pounds + 1..s.len() - pounds - 1].to_owned()
763 }
764
765 pub fn parse_lit_byte_str(s: &str) -> Vec<u8> {
766 assert_eq!(byte(s, 0), b'b');
767 match byte(s, 1) {
768 b'"' => parse_lit_byte_str_cooked(s),
769 b'r' => parse_lit_byte_str_raw(s),
770 _ => unreachable!(),
771 }
772 }
773
David Tolnay76ebcdd2018-01-05 17:07:26 -0800774 // Clippy false positive
775 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
776 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800777 fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> {
778 assert_eq!(byte(s, 0), b'b');
779 assert_eq!(byte(s, 1), b'"');
780 s = &s[2..];
781
782 // We're going to want to have slices which don't respect codepoint boundaries.
783 let mut s = s.as_bytes();
784
785 let mut out = Vec::new();
786 'outer: loop {
787 let byte = match byte(s, 0) {
788 b'"' => break,
789 b'\\' => {
790 let b = byte(s, 1);
791 s = &s[2..];
792 match b {
793 b'x' => {
794 let (b, rest) = backslash_x(s);
795 s = rest;
796 b
797 }
798 b'n' => b'\n',
799 b'r' => b'\r',
800 b't' => b'\t',
801 b'\\' => b'\\',
802 b'0' => b'\0',
803 b'\'' => b'\'',
804 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800805 b'\r' | b'\n' => loop {
806 let byte = byte(s, 0);
David Tolnay76ebcdd2018-01-05 17:07:26 -0800807 let ch = char::from_u32(u32::from(byte)).unwrap();
David Tolnay61037c62018-01-05 16:21:03 -0800808 if ch.is_whitespace() {
809 s = &s[1..];
810 } else {
811 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800812 }
David Tolnay61037c62018-01-05 16:21:03 -0800813 },
814 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800815 }
816 }
817 b'\r' => {
818 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
819 s = &s[2..];
820 b'\n'
821 }
822 b => {
823 s = &s[1..];
824 b
825 }
826 };
827 out.push(byte);
828 }
829
830 assert_eq!(s, b"\"");
831 out
832 }
833
834 fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> {
835 assert_eq!(byte(s, 0), b'b');
836 parse_lit_str_raw(&s[1..]).into_bytes()
837 }
838
839 pub fn parse_lit_byte(s: &str) -> u8 {
840 assert_eq!(byte(s, 0), b'b');
841 assert_eq!(byte(s, 1), b'\'');
842
843 // We're going to want to have slices which don't respect codepoint boundaries.
844 let mut s = s[2..].as_bytes();
845
846 let b = match byte(s, 0) {
847 b'\\' => {
848 let b = byte(s, 1);
849 s = &s[2..];
850 match b {
851 b'x' => {
852 let (b, rest) = backslash_x(s);
853 s = rest;
854 b
855 }
856 b'n' => b'\n',
857 b'r' => b'\r',
858 b't' => b'\t',
859 b'\\' => b'\\',
860 b'0' => b'\0',
861 b'\'' => b'\'',
862 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800863 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800864 }
865 }
866 b => {
867 s = &s[1..];
868 b
869 }
870 };
871
872 assert_eq!(byte(s, 0), b'\'');
873 b
874 }
875
876 pub fn parse_lit_char(mut s: &str) -> char {
877 assert_eq!(byte(s, 0), b'\'');
878 s = &s[1..];
879
880 let ch = match byte(s, 0) {
881 b'\\' => {
882 let b = byte(s, 1);
883 s = &s[2..];
884 match b {
885 b'x' => {
886 let (byte, rest) = backslash_x(s);
887 s = rest;
888 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800889 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800890 }
891 b'u' => {
892 let (chr, rest) = backslash_u(s);
893 s = rest;
894 chr
895 }
896 b'n' => '\n',
897 b'r' => '\r',
898 b't' => '\t',
899 b'\\' => '\\',
900 b'0' => '\0',
901 b'\'' => '\'',
902 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800903 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800904 }
905 }
906 _ => {
907 let ch = next_chr(s);
908 s = &s[ch.len_utf8()..];
909 ch
910 }
911 };
912 assert_eq!(s, "\'", "Expected end of char literal");
913 ch
914 }
915
916 fn backslash_x<S>(s: &S) -> (u8, &S)
David Tolnay61037c62018-01-05 16:21:03 -0800917 where
918 S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
David Tolnay360efd22018-01-04 23:35:26 -0800919 {
920 let mut ch = 0;
921 let b0 = byte(s, 0);
922 let b1 = byte(s, 1);
923 ch += 0x10 * match b0 {
924 b'0'...b'9' => b0 - b'0',
925 b'a'...b'f' => 10 + (b0 - b'a'),
926 b'A'...b'F' => 10 + (b0 - b'A'),
927 _ => panic!("unexpected non-hex character after \\x"),
928 };
David Tolnay76ebcdd2018-01-05 17:07:26 -0800929 ch += match b1 {
David Tolnay360efd22018-01-04 23:35:26 -0800930 b'0'...b'9' => b1 - b'0',
931 b'a'...b'f' => 10 + (b1 - b'a'),
932 b'A'...b'F' => 10 + (b1 - b'A'),
933 _ => panic!("unexpected non-hex character after \\x"),
934 };
935 (ch, &s[2..])
936 }
937
938 fn backslash_u(mut s: &str) -> (char, &str) {
939 if byte(s, 0) != b'{' {
940 panic!("expected {{ after \\u");
941 }
942 s = &s[1..];
943
944 let mut ch = 0;
945 for _ in 0..6 {
946 let b = byte(s, 0);
947 match b {
948 b'0'...b'9' => {
949 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800950 ch += u32::from(b - b'0');
David Tolnay360efd22018-01-04 23:35:26 -0800951 s = &s[1..];
952 }
953 b'a'...b'f' => {
954 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800955 ch += u32::from(10 + b - b'a');
David Tolnay360efd22018-01-04 23:35:26 -0800956 s = &s[1..];
957 }
958 b'A'...b'F' => {
959 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800960 ch += u32::from(10 + b - b'A');
David Tolnay360efd22018-01-04 23:35:26 -0800961 s = &s[1..];
962 }
963 b'}' => break,
964 _ => panic!("unexpected non-hex character after \\u"),
965 }
966 }
967 assert!(byte(s, 0) == b'}');
968 s = &s[1..];
969
970 if let Some(ch) = char::from_u32(ch) {
971 (ch, s)
972 } else {
973 panic!("character code {:x} is not a valid unicode character", ch);
974 }
975 }
976
977 pub fn parse_lit_int(mut s: &str) -> Option<u64> {
978 let base = match (byte(s, 0), byte(s, 1)) {
979 (b'0', b'x') => {
980 s = &s[2..];
981 16
982 }
983 (b'0', b'o') => {
984 s = &s[2..];
985 8
986 }
987 (b'0', b'b') => {
988 s = &s[2..];
989 2
990 }
991 (b'0'...b'9', _) => 10,
992 _ => unreachable!(),
993 };
994
995 let mut value = 0u64;
996 loop {
997 let b = byte(s, 0);
998 let digit = match b {
David Tolnay76ebcdd2018-01-05 17:07:26 -0800999 b'0'...b'9' => u64::from(b - b'0'),
1000 b'a'...b'f' if base > 10 => 10 + u64::from(b - b'a'),
1001 b'A'...b'F' if base > 10 => 10 + u64::from(b - b'A'),
David Tolnay360efd22018-01-04 23:35:26 -08001002 b'_' => {
1003 s = &s[1..];
1004 continue;
1005 }
1006 // NOTE: Looking at a floating point literal, we don't want to
1007 // consider these integers.
1008 b'.' if base == 10 => return None,
1009 b'e' | b'E' if base == 10 => return None,
1010 _ => break,
1011 };
1012
1013 if digit >= base {
1014 panic!("Unexpected digit {:x} out of base range", digit);
1015 }
1016
1017 value = match value.checked_mul(base) {
1018 Some(value) => value,
1019 None => return None,
1020 };
1021 value = match value.checked_add(digit) {
1022 Some(value) => value,
1023 None => return None,
1024 };
1025 s = &s[1..];
1026 }
1027
1028 Some(value)
1029 }
1030
1031 pub fn parse_lit_float(input: &str) -> f64 {
1032 // Rust's floating point literals are very similar to the ones parsed by
1033 // the standard library, except that rust's literals can contain
1034 // ignorable underscores. Let's remove those underscores.
1035 let mut bytes = input.to_owned().into_bytes();
1036 let mut write = 0;
1037 for read in 0..bytes.len() {
1038 if bytes[read] == b'_' {
1039 continue; // Don't increase write
David Tolnay76ebcdd2018-01-05 17:07:26 -08001040 }
1041 if write != read {
David Tolnay360efd22018-01-04 23:35:26 -08001042 let x = bytes[read];
1043 bytes[write] = x;
1044 }
1045 write += 1;
1046 }
1047 bytes.truncate(write);
1048 let input = String::from_utf8(bytes).unwrap();
David Tolnay76ebcdd2018-01-05 17:07:26 -08001049 let end = input.find('f').unwrap_or_else(|| input.len());
David Tolnay360efd22018-01-04 23:35:26 -08001050 input[..end].parse().unwrap()
1051 }
1052
1053 pub fn to_literal(s: &str) -> Literal {
1054 let stream = s.parse::<TokenStream>().unwrap();
Alex Crichton9a4dca22018-03-28 06:32:19 -07001055 match stream.into_iter().next().unwrap() {
1056 TokenTree::Literal(l) => l,
David Tolnay360efd22018-01-04 23:35:26 -08001057 _ => unreachable!(),
David Tolnayf17fd2f2016-10-07 23:38:08 -07001058 }
1059 }
David Tolnayf4bbbd92016-09-23 14:41:55 -07001060}