blob: a1e5844cdb6e9edb1d619a10d8d4adf2f0c6bfb2 [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")]
18use {ParseError, Synom};
19
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 Tolnay360efd22018-01-04 23:35:26 -080025ast_enum_of_structs! {
David Tolnayabf5c2e2018-01-06 23:30:04 -080026 /// A Rust literal such as a string or integer or boolean.
David Tolnay614a0142018-01-07 10:25:43 -080027 ///
David Tolnay461d98e2018-01-07 11:07:19 -080028 /// *This type is available if Syn is built with the `"derive"` or `"full"`
29 /// feature.*
30 ///
David Tolnay614a0142018-01-07 10:25:43 -080031 /// # Syntax tree enum
32 ///
33 /// This type is a [syntax tree enum].
34 ///
35 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
David Tolnay360efd22018-01-04 23:35:26 -080036 pub enum Lit {
David Tolnayabf5c2e2018-01-06 23:30:04 -080037 /// A UTF-8 string literal: `"foo"`.
David Tolnay461d98e2018-01-07 11:07:19 -080038 ///
39 /// *This type is available if Syn is built with the `"derive"` or
40 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080041 pub Str(LitStr #manual_extra_traits {
42 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080043 }),
Alex Crichtonccbb45d2017-05-23 10:58:24 -070044
David Tolnayabf5c2e2018-01-06 23:30:04 -080045 /// A byte string literal: `b"foo"`.
David Tolnay461d98e2018-01-07 11:07:19 -080046 ///
47 /// *This type is available if Syn is built with the `"derive"` or
48 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080049 pub ByteStr(LitByteStr #manual_extra_traits {
50 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080051 }),
52
David Tolnayabf5c2e2018-01-06 23:30:04 -080053 /// A byte literal: `b'f'`.
David Tolnay461d98e2018-01-07 11:07:19 -080054 ///
55 /// *This type is available if Syn is built with the `"derive"` or
56 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080057 pub Byte(LitByte #manual_extra_traits {
58 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080059 }),
60
David Tolnayabf5c2e2018-01-06 23:30:04 -080061 /// A character literal: `'a'`.
David Tolnay461d98e2018-01-07 11:07:19 -080062 ///
63 /// *This type is available if Syn is built with the `"derive"` or
64 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080065 pub Char(LitChar #manual_extra_traits {
66 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080067 }),
68
David Tolnayabf5c2e2018-01-06 23:30:04 -080069 /// An integer literal: `1` or `1u16`.
David Tolnay360efd22018-01-04 23:35:26 -080070 ///
71 /// Holds up to 64 bits of data. Use `LitVerbatim` for any larger
72 /// integer literal.
David Tolnay461d98e2018-01-07 11:07:19 -080073 ///
74 /// *This type is available if Syn is built with the `"derive"` or
75 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080076 pub Int(LitInt #manual_extra_traits {
77 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080078 }),
79
David Tolnayabf5c2e2018-01-06 23:30:04 -080080 /// A floating point literal: `1f64` or `1.0e10f64`.
David Tolnay360efd22018-01-04 23:35:26 -080081 ///
82 /// Must be finite. May not be infinte or NaN.
David Tolnay461d98e2018-01-07 11:07:19 -080083 ///
84 /// *This type is available if Syn is built with the `"derive"` or
85 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080086 pub Float(LitFloat #manual_extra_traits {
87 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080088 }),
89
David Tolnayabf5c2e2018-01-06 23:30:04 -080090 /// A boolean literal: `true` or `false`.
David Tolnay461d98e2018-01-07 11:07:19 -080091 ///
92 /// *This type is available if Syn is built with the `"derive"` or
93 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080094 pub Bool(LitBool #manual_extra_traits {
95 pub value: bool,
96 pub span: Span,
97 }),
98
David Tolnayabf5c2e2018-01-06 23:30:04 -080099 /// A raw token literal not interpreted by Syn, possibly because it
100 /// represents an integer larger than 64 bits.
David Tolnay461d98e2018-01-07 11:07:19 -0800101 ///
102 /// *This type is available if Syn is built with the `"derive"` or
103 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800104 pub Verbatim(LitVerbatim #manual_extra_traits {
105 pub token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -0800106 }),
107 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700108}
109
David Tolnay360efd22018-01-04 23:35:26 -0800110impl LitStr {
111 pub fn new(value: &str, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700112 let mut lit = Literal::string(value);
113 lit.set_span(span);
David Tolnay94d2b792018-04-29 12:26:10 -0700114 LitStr { token: lit }
David Tolnay360efd22018-01-04 23:35:26 -0800115 }
116
117 pub fn value(&self) -> String {
118 value::parse_lit_str(&self.token.to_string())
119 }
David Tolnayd53ac2b2018-01-27 19:00:06 -0800120
121 /// Parse a syntax tree node from the content of this string literal.
122 ///
123 /// All spans in the syntax tree will point to the span of this `LitStr`.
124 #[cfg(feature = "parsing")]
125 pub fn parse<T: Synom>(&self) -> Result<T, ParseError> {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700126 use proc_macro2::Group;
127
David Tolnayd53ac2b2018-01-27 19:00:06 -0800128 // Parse string literal into a token stream with every span equal to the
129 // original literal's span.
130 fn spanned_tokens(s: &LitStr) -> Result<TokenStream, ParseError> {
131 let stream = ::parse_str(&s.value())?;
Alex Crichton9a4dca22018-03-28 06:32:19 -0700132 Ok(respan_token_stream(stream, s.span()))
David Tolnayd53ac2b2018-01-27 19:00:06 -0800133 }
134
135 // Token stream with every span replaced by the given one.
136 fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
David Tolnay94d2b792018-04-29 12:26:10 -0700137 stream
138 .into_iter()
139 .map(|token| respan_token_tree(token, span))
140 .collect()
David Tolnayd53ac2b2018-01-27 19:00:06 -0800141 }
142
143 // Token tree with every span replaced by the given one.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700144 fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
145 match token {
146 TokenTree::Group(ref mut g) => {
147 let stream = respan_token_stream(g.stream().clone(), span);
148 *g = Group::new(g.delimiter(), stream);
149 g.set_span(span);
150 }
151 ref mut other => other.set_span(span),
David Tolnayd53ac2b2018-01-27 19:00:06 -0800152 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700153 token
David Tolnayd53ac2b2018-01-27 19:00:06 -0800154 }
155
156 spanned_tokens(self).and_then(::parse2)
157 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700158
159 pub fn span(&self) -> Span {
160 self.token.span()
161 }
162
163 pub fn set_span(&mut self, span: Span) {
164 self.token.set_span(span)
165 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700166}
167
David Tolnay360efd22018-01-04 23:35:26 -0800168impl LitByteStr {
169 pub fn new(value: &[u8], span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700170 let mut token = Literal::byte_string(value);
171 token.set_span(span);
172 LitByteStr { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800173 }
174
175 pub fn value(&self) -> Vec<u8> {
176 value::parse_lit_byte_str(&self.token.to_string())
177 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700178
179 pub fn span(&self) -> Span {
180 self.token.span()
181 }
182
183 pub fn set_span(&mut self, span: Span) {
184 self.token.set_span(span)
185 }
David Tolnay360efd22018-01-04 23:35:26 -0800186}
187
188impl LitByte {
189 pub fn new(value: u8, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700190 let mut token = Literal::u8_suffixed(value);
191 token.set_span(span);
192 LitByte { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800193 }
194
195 pub fn value(&self) -> u8 {
196 value::parse_lit_byte(&self.token.to_string())
197 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700198
199 pub fn span(&self) -> Span {
200 self.token.span()
201 }
202
203 pub fn set_span(&mut self, span: Span) {
204 self.token.set_span(span)
205 }
David Tolnay360efd22018-01-04 23:35:26 -0800206}
207
208impl LitChar {
209 pub fn new(value: char, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700210 let mut token = Literal::character(value);
211 token.set_span(span);
212 LitChar { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800213 }
214
215 pub fn value(&self) -> char {
216 value::parse_lit_char(&self.token.to_string())
217 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700218
219 pub fn span(&self) -> Span {
220 self.token.span()
221 }
222
223 pub fn set_span(&mut self, span: Span) {
224 self.token.set_span(span)
225 }
David Tolnay360efd22018-01-04 23:35:26 -0800226}
227
228impl LitInt {
229 pub fn new(value: u64, suffix: IntSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700230 let mut token = match suffix {
231 IntSuffix::Isize => Literal::isize_suffixed(value as isize),
232 IntSuffix::I8 => Literal::i8_suffixed(value as i8),
233 IntSuffix::I16 => Literal::i16_suffixed(value as i16),
234 IntSuffix::I32 => Literal::i32_suffixed(value as i32),
235 IntSuffix::I64 => Literal::i64_suffixed(value as i64),
236 IntSuffix::I128 => value::to_literal(&format!("{}i128", value)),
237 IntSuffix::Usize => Literal::usize_suffixed(value as usize),
238 IntSuffix::U8 => Literal::u8_suffixed(value as u8),
239 IntSuffix::U16 => Literal::u16_suffixed(value as u16),
240 IntSuffix::U32 => Literal::u32_suffixed(value as u32),
241 IntSuffix::U64 => Literal::u64_suffixed(value),
242 IntSuffix::U128 => value::to_literal(&format!("{}u128", value)),
243 IntSuffix::None => Literal::u64_unsuffixed(value),
244 };
245 token.set_span(span);
246 LitInt { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800247 }
248
249 pub fn value(&self) -> u64 {
250 value::parse_lit_int(&self.token.to_string()).unwrap()
251 }
252
253 pub fn suffix(&self) -> IntSuffix {
254 let value = self.token.to_string();
255 for (s, suffix) in vec![
256 ("i8", IntSuffix::I8),
257 ("i16", IntSuffix::I16),
258 ("i32", IntSuffix::I32),
259 ("i64", IntSuffix::I64),
260 ("i128", IntSuffix::I128),
261 ("isize", IntSuffix::Isize),
262 ("u8", IntSuffix::U8),
263 ("u16", IntSuffix::U16),
264 ("u32", IntSuffix::U32),
265 ("u64", IntSuffix::U64),
266 ("u128", IntSuffix::U128),
267 ("usize", IntSuffix::Usize),
268 ] {
269 if value.ends_with(s) {
270 return suffix;
271 }
272 }
273 IntSuffix::None
274 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700275
276 pub fn span(&self) -> Span {
277 self.token.span()
278 }
279
280 pub fn set_span(&mut self, span: Span) {
281 self.token.set_span(span)
282 }
David Tolnay360efd22018-01-04 23:35:26 -0800283}
284
285impl LitFloat {
286 pub fn new(value: f64, suffix: FloatSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700287 let mut token = match suffix {
288 FloatSuffix::F32 => Literal::f32_suffixed(value as f32),
289 FloatSuffix::F64 => Literal::f64_suffixed(value),
290 FloatSuffix::None => Literal::f64_unsuffixed(value),
291 };
292 token.set_span(span);
293 LitFloat { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800294 }
295
296 pub fn value(&self) -> f64 {
297 value::parse_lit_float(&self.token.to_string())
298 }
299
300 pub fn suffix(&self) -> FloatSuffix {
301 let value = self.token.to_string();
David Tolnay61037c62018-01-05 16:21:03 -0800302 for (s, suffix) in vec![("f32", FloatSuffix::F32), ("f64", FloatSuffix::F64)] {
David Tolnay360efd22018-01-04 23:35:26 -0800303 if value.ends_with(s) {
304 return suffix;
305 }
306 }
307 FloatSuffix::None
308 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700309
310 pub fn span(&self) -> Span {
311 self.token.span()
312 }
313
314 pub fn set_span(&mut self, span: Span) {
315 self.token.set_span(span)
316 }
David Tolnay360efd22018-01-04 23:35:26 -0800317}
318
319macro_rules! lit_extra_traits {
320 ($ty:ident, $field:ident) => {
321 #[cfg(feature = "extra-traits")]
322 impl Eq for $ty {}
323
324 #[cfg(feature = "extra-traits")]
325 impl PartialEq for $ty {
326 fn eq(&self, other: &Self) -> bool {
327 self.$field.to_string() == other.$field.to_string()
328 }
329 }
330
331 #[cfg(feature = "extra-traits")]
332 impl Hash for $ty {
333 fn hash<H>(&self, state: &mut H)
334 where
335 H: Hasher,
336 {
337 self.$field.to_string().hash(state);
338 }
David Tolnay9c76bcb2017-12-26 23:14:59 -0500339 }
David Tolnay94d2b792018-04-29 12:26:10 -0700340 };
David Tolnayf4bbbd92016-09-23 14:41:55 -0700341}
342
Alex Crichton9a4dca22018-03-28 06:32:19 -0700343impl LitVerbatim {
344 pub fn span(&self) -> Span {
345 self.token.span()
346 }
347
348 pub fn set_span(&mut self, span: Span) {
349 self.token.set_span(span)
350 }
351}
352
David Tolnay360efd22018-01-04 23:35:26 -0800353lit_extra_traits!(LitStr, token);
354lit_extra_traits!(LitByteStr, token);
355lit_extra_traits!(LitByte, token);
356lit_extra_traits!(LitChar, token);
357lit_extra_traits!(LitInt, token);
358lit_extra_traits!(LitFloat, token);
359lit_extra_traits!(LitBool, value);
360lit_extra_traits!(LitVerbatim, token);
361
362ast_enum! {
David Tolnay05658502018-01-07 09:56:37 -0800363 /// The style of a string literal, either plain quoted or a raw string like
David Tolnayabf5c2e2018-01-06 23:30:04 -0800364 /// `r##"data"##`.
David Tolnay461d98e2018-01-07 11:07:19 -0800365 ///
366 /// *This type is available if Syn is built with the `"derive"` or `"full"`
367 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800368 pub enum StrStyle #no_visit {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800369 /// An ordinary string like `"data"`.
David Tolnay360efd22018-01-04 23:35:26 -0800370 Cooked,
David Tolnayabf5c2e2018-01-06 23:30:04 -0800371 /// A raw string like `r##"data"##`.
David Tolnay360efd22018-01-04 23:35:26 -0800372 ///
373 /// The unsigned integer is the number of `#` symbols used.
374 Raw(usize),
Alex Crichton62a0a592017-05-22 13:58:53 -0700375 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700376}
377
David Tolnay360efd22018-01-04 23:35:26 -0800378ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800379 /// The suffix on an integer literal if any, like the `u8` in `127u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800380 ///
381 /// *This type is available if Syn is built with the `"derive"` or `"full"`
382 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800383 pub enum IntSuffix #no_visit {
384 I8,
385 I16,
386 I32,
387 I64,
388 I128,
389 Isize,
390 U8,
391 U16,
392 U32,
393 U64,
394 U128,
395 Usize,
396 None,
Pascal Hertleif36342c52016-10-19 10:31:42 +0200397 }
398}
399
David Tolnay360efd22018-01-04 23:35:26 -0800400ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800401 /// The suffix on a floating point literal if any, like the `f32` in
402 /// `1.0f32`.
David Tolnay461d98e2018-01-07 11:07:19 -0800403 ///
404 /// *This type is available if Syn is built with the `"derive"` or `"full"`
405 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800406 pub enum FloatSuffix #no_visit {
407 F32,
408 F64,
409 None,
Alex Crichton2e0229c2017-05-23 09:34:50 -0700410 }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800411}
412
413#[cfg(feature = "parsing")]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700414pub mod parsing {
415 use super::*;
David Tolnaydfc886b2018-01-06 08:03:09 -0800416 use buffer::Cursor;
David Tolnay203557a2017-12-27 23:59:33 -0500417 use parse_error;
418 use synom::PResult;
David Tolnay94d2b792018-04-29 12:26:10 -0700419 use synom::Synom;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700420
Alex Crichton954046c2017-05-30 21:49:42 -0700421 impl Synom for Lit {
Michael Layzell92639a52017-06-01 00:07:44 -0400422 fn parse(input: Cursor) -> PResult<Self> {
Michael Layzell589a8f42017-06-02 19:47:01 -0400423 match input.literal() {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700424 Some((lit, rest)) => {
David Tolnay7037c9b2018-01-23 09:34:09 -0800425 if lit.to_string().starts_with('/') {
426 // Doc comment literal which is not a Syn literal
427 parse_error()
428 } else {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700429 Ok((Lit::new(lit), rest))
David Tolnay7037c9b2018-01-23 09:34:09 -0800430 }
431 }
David Tolnay73c98de2017-12-31 15:56:56 -0500432 _ => match input.term() {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700433 Some((term, rest)) => Ok((
David Tolnay360efd22018-01-04 23:35:26 -0800434 Lit::Bool(LitBool {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700435 value: if term.to_string() == "true" {
David Tolnay360efd22018-01-04 23:35:26 -0800436 true
Alex Crichtona74a1c82018-05-16 10:20:44 -0700437 } else if term.to_string() == "false" {
David Tolnay360efd22018-01-04 23:35:26 -0800438 false
439 } else {
440 return parse_error();
David Tolnay51382052017-12-27 13:46:21 -0500441 },
Alex Crichton9a4dca22018-03-28 06:32:19 -0700442 span: term.span(),
David Tolnay360efd22018-01-04 23:35:26 -0800443 }),
444 rest,
445 )),
Michael Layzell589a8f42017-06-02 19:47:01 -0400446 _ => parse_error(),
David Tolnay51382052017-12-27 13:46:21 -0500447 },
Michael Layzell589a8f42017-06-02 19:47:01 -0400448 }
David Tolnayfa0edf22016-09-23 22:58:24 -0700449 }
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800450
451 fn description() -> Option<&'static str> {
452 Some("literal")
453 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700454 }
David Tolnay360efd22018-01-04 23:35:26 -0800455
456 impl_synom!(LitStr "string literal" switch!(
457 syn!(Lit),
458 Lit::Str(lit) => value!(lit)
459 |
460 _ => reject!()
461 ));
462
463 impl_synom!(LitByteStr "byte string literal" switch!(
464 syn!(Lit),
465 Lit::ByteStr(lit) => value!(lit)
466 |
467 _ => reject!()
468 ));
469
470 impl_synom!(LitByte "byte literal" switch!(
471 syn!(Lit),
472 Lit::Byte(lit) => value!(lit)
473 |
474 _ => reject!()
475 ));
476
477 impl_synom!(LitChar "character literal" switch!(
478 syn!(Lit),
479 Lit::Char(lit) => value!(lit)
480 |
481 _ => reject!()
482 ));
483
484 impl_synom!(LitInt "integer literal" switch!(
485 syn!(Lit),
486 Lit::Int(lit) => value!(lit)
487 |
488 _ => reject!()
489 ));
490
491 impl_synom!(LitFloat "floating point literal" switch!(
492 syn!(Lit),
493 Lit::Float(lit) => value!(lit)
494 |
495 _ => reject!()
496 ));
497
498 impl_synom!(LitBool "boolean literal" switch!(
499 syn!(Lit),
500 Lit::Bool(lit) => value!(lit)
501 |
502 _ => reject!()
503 ));
David Tolnayf4bbbd92016-09-23 14:41:55 -0700504}
505
506#[cfg(feature = "printing")]
507mod printing {
508 use super::*;
Alex Crichtona74a1c82018-05-16 10:20:44 -0700509 use quote::{ToTokens, TokenStreamExt};
510 use proc_macro2::TokenStream;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700511
David Tolnay360efd22018-01-04 23:35:26 -0800512 impl ToTokens for LitStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700513 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700514 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800515 }
516 }
517
518 impl ToTokens for LitByteStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700519 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700520 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800521 }
522 }
523
524 impl ToTokens for LitByte {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700525 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700526 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800527 }
528 }
529
530 impl ToTokens for LitChar {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700531 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700532 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800533 }
534 }
535
536 impl ToTokens for LitInt {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700537 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700538 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800539 }
540 }
541
542 impl ToTokens for LitFloat {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700543 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700544 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800545 }
546 }
547
548 impl ToTokens for LitBool {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700549 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700550 let s = if self.value { "true" } else { "false" };
Alex Crichtona74a1c82018-05-16 10:20:44 -0700551 tokens.append(Ident::new(s, self.span));
David Tolnay360efd22018-01-04 23:35:26 -0800552 }
553 }
554
555 impl ToTokens for LitVerbatim {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700556 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700557 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800558 }
559 }
560}
561
562mod value {
563 use super::*;
David Tolnay94d2b792018-04-29 12:26:10 -0700564 use proc_macro2::TokenStream;
David Tolnay360efd22018-01-04 23:35:26 -0800565 use std::char;
566 use std::ops::{Index, RangeFrom};
David Tolnay360efd22018-01-04 23:35:26 -0800567
David Tolnay7d1d1282018-01-06 16:10:51 -0800568 impl Lit {
David Tolnay780292d2018-01-22 23:26:44 -0800569 /// Interpret a Syn literal from a proc-macro2 literal.
570 ///
571 /// Not all proc-macro2 literals are valid Syn literals. In particular,
572 /// doc comments are considered by proc-macro2 to be literals but in Syn
573 /// they are [`Attribute`].
574 ///
575 /// [`Attribute`]: struct.Attribute.html
576 ///
577 /// # Panics
578 ///
579 /// Panics if the input is a doc comment literal.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700580 pub fn new(token: Literal) -> Self {
David Tolnay7d1d1282018-01-06 16:10:51 -0800581 let value = token.to_string();
582
583 match value::byte(&value, 0) {
David Tolnay94d2b792018-04-29 12:26:10 -0700584 b'"' | b'r' => return Lit::Str(LitStr { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800585 b'b' => match value::byte(&value, 1) {
David Tolnay94d2b792018-04-29 12:26:10 -0700586 b'"' | b'r' => return Lit::ByteStr(LitByteStr { token: token }),
587 b'\'' => return Lit::Byte(LitByte { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800588 _ => {}
589 },
David Tolnay94d2b792018-04-29 12:26:10 -0700590 b'\'' => return Lit::Char(LitChar { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800591 b'0'...b'9' => if number_is_int(&value) {
David Tolnay94d2b792018-04-29 12:26:10 -0700592 return Lit::Int(LitInt { token: token });
David Tolnay7d1d1282018-01-06 16:10:51 -0800593 } else if number_is_float(&value) {
David Tolnay94d2b792018-04-29 12:26:10 -0700594 return Lit::Float(LitFloat { token: token });
David Tolnay7d1d1282018-01-06 16:10:51 -0800595 } else {
596 // number overflow
David Tolnay94d2b792018-04-29 12:26:10 -0700597 return Lit::Verbatim(LitVerbatim { token: token });
David Tolnay7d1d1282018-01-06 16:10:51 -0800598 },
599 _ => if value == "true" || value == "false" {
600 return Lit::Bool(LitBool {
601 value: value == "true",
Alex Crichton9a4dca22018-03-28 06:32:19 -0700602 span: token.span(),
David Tolnay7d1d1282018-01-06 16:10:51 -0800603 });
604 },
605 }
606
607 panic!("Unrecognized literal: {}", value);
608 }
609 }
610
611 fn number_is_int(value: &str) -> bool {
612 if number_is_float(value) {
613 false
614 } else {
615 value::parse_lit_int(value).is_some()
616 }
617 }
618
619 fn number_is_float(value: &str) -> bool {
620 if value.contains('.') {
621 true
622 } else if value.starts_with("0x") || value.ends_with("size") {
623 false
624 } else {
625 value.contains('e') || value.contains('E')
626 }
627 }
628
David Tolnay360efd22018-01-04 23:35:26 -0800629 /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
630 /// past the end of the input buffer.
631 pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
632 let s = s.as_ref();
633 if idx < s.len() {
634 s[idx]
635 } else {
636 0
637 }
638 }
639
640 fn next_chr(s: &str) -> char {
641 s.chars().next().unwrap_or('\0')
642 }
643
644 pub fn parse_lit_str(s: &str) -> String {
645 match byte(s, 0) {
646 b'"' => parse_lit_str_cooked(s),
647 b'r' => parse_lit_str_raw(s),
648 _ => unreachable!(),
649 }
650 }
651
David Tolnay76ebcdd2018-01-05 17:07:26 -0800652 // Clippy false positive
653 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
654 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800655 fn parse_lit_str_cooked(mut s: &str) -> String {
656 assert_eq!(byte(s, 0), b'"');
657 s = &s[1..];
658
659 let mut out = String::new();
660 'outer: loop {
661 let ch = match byte(s, 0) {
662 b'"' => break,
663 b'\\' => {
664 let b = byte(s, 1);
665 s = &s[2..];
666 match b {
667 b'x' => {
668 let (byte, rest) = backslash_x(s);
669 s = rest;
670 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800671 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800672 }
673 b'u' => {
David Tolnay76ebcdd2018-01-05 17:07:26 -0800674 let (chr, rest) = backslash_u(s);
David Tolnay360efd22018-01-04 23:35:26 -0800675 s = rest;
676 chr
677 }
678 b'n' => '\n',
679 b'r' => '\r',
680 b't' => '\t',
681 b'\\' => '\\',
682 b'0' => '\0',
683 b'\'' => '\'',
684 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800685 b'\r' | b'\n' => loop {
686 let ch = next_chr(s);
687 if ch.is_whitespace() {
688 s = &s[ch.len_utf8()..];
689 } else {
690 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800691 }
David Tolnay61037c62018-01-05 16:21:03 -0800692 },
693 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800694 }
695 }
696 b'\r' => {
697 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
698 s = &s[2..];
699 '\n'
700 }
701 _ => {
702 let ch = next_chr(s);
703 s = &s[ch.len_utf8()..];
704 ch
705 }
706 };
707 out.push(ch);
708 }
709
710 assert_eq!(s, "\"");
711 out
712 }
713
714 fn parse_lit_str_raw(mut s: &str) -> String {
715 assert_eq!(byte(s, 0), b'r');
716 s = &s[1..];
717
718 let mut pounds = 0;
719 while byte(s, pounds) == b'#' {
720 pounds += 1;
721 }
722 assert_eq!(byte(s, pounds), b'"');
723 assert_eq!(byte(s, s.len() - pounds - 1), b'"');
724 for end in s[s.len() - pounds..].bytes() {
725 assert_eq!(end, b'#');
726 }
727
728 s[pounds + 1..s.len() - pounds - 1].to_owned()
729 }
730
731 pub fn parse_lit_byte_str(s: &str) -> Vec<u8> {
732 assert_eq!(byte(s, 0), b'b');
733 match byte(s, 1) {
734 b'"' => parse_lit_byte_str_cooked(s),
735 b'r' => parse_lit_byte_str_raw(s),
736 _ => unreachable!(),
737 }
738 }
739
David Tolnay76ebcdd2018-01-05 17:07:26 -0800740 // Clippy false positive
741 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
742 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800743 fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> {
744 assert_eq!(byte(s, 0), b'b');
745 assert_eq!(byte(s, 1), b'"');
746 s = &s[2..];
747
748 // We're going to want to have slices which don't respect codepoint boundaries.
749 let mut s = s.as_bytes();
750
751 let mut out = Vec::new();
752 'outer: loop {
753 let byte = match byte(s, 0) {
754 b'"' => break,
755 b'\\' => {
756 let b = byte(s, 1);
757 s = &s[2..];
758 match b {
759 b'x' => {
760 let (b, rest) = backslash_x(s);
761 s = rest;
762 b
763 }
764 b'n' => b'\n',
765 b'r' => b'\r',
766 b't' => b'\t',
767 b'\\' => b'\\',
768 b'0' => b'\0',
769 b'\'' => b'\'',
770 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800771 b'\r' | b'\n' => loop {
772 let byte = byte(s, 0);
David Tolnay76ebcdd2018-01-05 17:07:26 -0800773 let ch = char::from_u32(u32::from(byte)).unwrap();
David Tolnay61037c62018-01-05 16:21:03 -0800774 if ch.is_whitespace() {
775 s = &s[1..];
776 } else {
777 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800778 }
David Tolnay61037c62018-01-05 16:21:03 -0800779 },
780 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800781 }
782 }
783 b'\r' => {
784 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
785 s = &s[2..];
786 b'\n'
787 }
788 b => {
789 s = &s[1..];
790 b
791 }
792 };
793 out.push(byte);
794 }
795
796 assert_eq!(s, b"\"");
797 out
798 }
799
800 fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> {
801 assert_eq!(byte(s, 0), b'b');
802 parse_lit_str_raw(&s[1..]).into_bytes()
803 }
804
805 pub fn parse_lit_byte(s: &str) -> u8 {
806 assert_eq!(byte(s, 0), b'b');
807 assert_eq!(byte(s, 1), b'\'');
808
809 // We're going to want to have slices which don't respect codepoint boundaries.
810 let mut s = s[2..].as_bytes();
811
812 let b = match byte(s, 0) {
813 b'\\' => {
814 let b = byte(s, 1);
815 s = &s[2..];
816 match b {
817 b'x' => {
818 let (b, rest) = backslash_x(s);
819 s = rest;
820 b
821 }
822 b'n' => b'\n',
823 b'r' => b'\r',
824 b't' => b'\t',
825 b'\\' => b'\\',
826 b'0' => b'\0',
827 b'\'' => b'\'',
828 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800829 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800830 }
831 }
832 b => {
833 s = &s[1..];
834 b
835 }
836 };
837
838 assert_eq!(byte(s, 0), b'\'');
839 b
840 }
841
842 pub fn parse_lit_char(mut s: &str) -> char {
843 assert_eq!(byte(s, 0), b'\'');
844 s = &s[1..];
845
846 let ch = match byte(s, 0) {
847 b'\\' => {
848 let b = byte(s, 1);
849 s = &s[2..];
850 match b {
851 b'x' => {
852 let (byte, rest) = backslash_x(s);
853 s = rest;
854 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800855 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800856 }
857 b'u' => {
858 let (chr, rest) = backslash_u(s);
859 s = rest;
860 chr
861 }
862 b'n' => '\n',
863 b'r' => '\r',
864 b't' => '\t',
865 b'\\' => '\\',
866 b'0' => '\0',
867 b'\'' => '\'',
868 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800869 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800870 }
871 }
872 _ => {
873 let ch = next_chr(s);
874 s = &s[ch.len_utf8()..];
875 ch
876 }
877 };
878 assert_eq!(s, "\'", "Expected end of char literal");
879 ch
880 }
881
882 fn backslash_x<S>(s: &S) -> (u8, &S)
David Tolnay61037c62018-01-05 16:21:03 -0800883 where
884 S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
David Tolnay360efd22018-01-04 23:35:26 -0800885 {
886 let mut ch = 0;
887 let b0 = byte(s, 0);
888 let b1 = byte(s, 1);
889 ch += 0x10 * match b0 {
890 b'0'...b'9' => b0 - b'0',
891 b'a'...b'f' => 10 + (b0 - b'a'),
892 b'A'...b'F' => 10 + (b0 - b'A'),
893 _ => panic!("unexpected non-hex character after \\x"),
894 };
David Tolnay76ebcdd2018-01-05 17:07:26 -0800895 ch += match b1 {
David Tolnay360efd22018-01-04 23:35:26 -0800896 b'0'...b'9' => b1 - b'0',
897 b'a'...b'f' => 10 + (b1 - b'a'),
898 b'A'...b'F' => 10 + (b1 - b'A'),
899 _ => panic!("unexpected non-hex character after \\x"),
900 };
901 (ch, &s[2..])
902 }
903
904 fn backslash_u(mut s: &str) -> (char, &str) {
905 if byte(s, 0) != b'{' {
906 panic!("expected {{ after \\u");
907 }
908 s = &s[1..];
909
910 let mut ch = 0;
911 for _ in 0..6 {
912 let b = byte(s, 0);
913 match b {
914 b'0'...b'9' => {
915 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800916 ch += u32::from(b - b'0');
David Tolnay360efd22018-01-04 23:35:26 -0800917 s = &s[1..];
918 }
919 b'a'...b'f' => {
920 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800921 ch += u32::from(10 + b - b'a');
David Tolnay360efd22018-01-04 23:35:26 -0800922 s = &s[1..];
923 }
924 b'A'...b'F' => {
925 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800926 ch += u32::from(10 + b - b'A');
David Tolnay360efd22018-01-04 23:35:26 -0800927 s = &s[1..];
928 }
929 b'}' => break,
930 _ => panic!("unexpected non-hex character after \\u"),
931 }
932 }
933 assert!(byte(s, 0) == b'}');
934 s = &s[1..];
935
936 if let Some(ch) = char::from_u32(ch) {
937 (ch, s)
938 } else {
939 panic!("character code {:x} is not a valid unicode character", ch);
940 }
941 }
942
943 pub fn parse_lit_int(mut s: &str) -> Option<u64> {
944 let base = match (byte(s, 0), byte(s, 1)) {
945 (b'0', b'x') => {
946 s = &s[2..];
947 16
948 }
949 (b'0', b'o') => {
950 s = &s[2..];
951 8
952 }
953 (b'0', b'b') => {
954 s = &s[2..];
955 2
956 }
957 (b'0'...b'9', _) => 10,
958 _ => unreachable!(),
959 };
960
961 let mut value = 0u64;
962 loop {
963 let b = byte(s, 0);
964 let digit = match b {
David Tolnay76ebcdd2018-01-05 17:07:26 -0800965 b'0'...b'9' => u64::from(b - b'0'),
966 b'a'...b'f' if base > 10 => 10 + u64::from(b - b'a'),
967 b'A'...b'F' if base > 10 => 10 + u64::from(b - b'A'),
David Tolnay360efd22018-01-04 23:35:26 -0800968 b'_' => {
969 s = &s[1..];
970 continue;
971 }
972 // NOTE: Looking at a floating point literal, we don't want to
973 // consider these integers.
974 b'.' if base == 10 => return None,
975 b'e' | b'E' if base == 10 => return None,
976 _ => break,
977 };
978
979 if digit >= base {
980 panic!("Unexpected digit {:x} out of base range", digit);
981 }
982
983 value = match value.checked_mul(base) {
984 Some(value) => value,
985 None => return None,
986 };
987 value = match value.checked_add(digit) {
988 Some(value) => value,
989 None => return None,
990 };
991 s = &s[1..];
992 }
993
994 Some(value)
995 }
996
997 pub fn parse_lit_float(input: &str) -> f64 {
998 // Rust's floating point literals are very similar to the ones parsed by
999 // the standard library, except that rust's literals can contain
1000 // ignorable underscores. Let's remove those underscores.
1001 let mut bytes = input.to_owned().into_bytes();
1002 let mut write = 0;
1003 for read in 0..bytes.len() {
1004 if bytes[read] == b'_' {
1005 continue; // Don't increase write
David Tolnay76ebcdd2018-01-05 17:07:26 -08001006 }
1007 if write != read {
David Tolnay360efd22018-01-04 23:35:26 -08001008 let x = bytes[read];
1009 bytes[write] = x;
1010 }
1011 write += 1;
1012 }
1013 bytes.truncate(write);
1014 let input = String::from_utf8(bytes).unwrap();
David Tolnay76ebcdd2018-01-05 17:07:26 -08001015 let end = input.find('f').unwrap_or_else(|| input.len());
David Tolnay360efd22018-01-04 23:35:26 -08001016 input[..end].parse().unwrap()
1017 }
1018
1019 pub fn to_literal(s: &str) -> Literal {
1020 let stream = s.parse::<TokenStream>().unwrap();
Alex Crichton9a4dca22018-03-28 06:32:19 -07001021 match stream.into_iter().next().unwrap() {
1022 TokenTree::Literal(l) => l,
David Tolnay360efd22018-01-04 23:35:26 -08001023 _ => unreachable!(),
David Tolnayf17fd2f2016-10-07 23:38:08 -07001024 }
1025 }
David Tolnayf4bbbd92016-09-23 14:41:55 -07001026}