blob: 6785f8837c9522a36aed06ba9ae2ca062ebbf266 [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")]
David Tolnay60fafad2018-02-03 09:18:03 -080013use proc_macro2::Term;
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 Tolnay360efd22018-01-04 23:35:26 -0800114 LitStr {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700115 token: lit,
David Tolnay360efd22018-01-04 23:35:26 -0800116 }
117 }
118
119 pub fn value(&self) -> String {
120 value::parse_lit_str(&self.token.to_string())
121 }
David Tolnayd53ac2b2018-01-27 19:00:06 -0800122
123 /// Parse a syntax tree node from the content of this string literal.
124 ///
125 /// All spans in the syntax tree will point to the span of this `LitStr`.
126 #[cfg(feature = "parsing")]
127 pub fn parse<T: Synom>(&self) -> Result<T, ParseError> {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700128 use proc_macro2::Group;
129
David Tolnayd53ac2b2018-01-27 19:00:06 -0800130 // Parse string literal into a token stream with every span equal to the
131 // original literal's span.
132 fn spanned_tokens(s: &LitStr) -> Result<TokenStream, ParseError> {
133 let stream = ::parse_str(&s.value())?;
Alex Crichton9a4dca22018-03-28 06:32:19 -0700134 Ok(respan_token_stream(stream, s.span()))
David Tolnayd53ac2b2018-01-27 19:00:06 -0800135 }
136
137 // Token stream with every span replaced by the given one.
138 fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
139 stream.into_iter().map(|token| respan_token_tree(token, span)).collect()
140 }
141
142 // Token tree with every span replaced by the given one.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700143 fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
144 match token {
145 TokenTree::Group(ref mut g) => {
146 let stream = respan_token_stream(g.stream().clone(), span);
147 *g = Group::new(g.delimiter(), stream);
148 g.set_span(span);
149 }
150 ref mut other => other.set_span(span),
David Tolnayd53ac2b2018-01-27 19:00:06 -0800151 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700152 token
David Tolnayd53ac2b2018-01-27 19:00:06 -0800153 }
154
155 spanned_tokens(self).and_then(::parse2)
156 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700157
158 pub fn span(&self) -> Span {
159 self.token.span()
160 }
161
162 pub fn set_span(&mut self, span: Span) {
163 self.token.set_span(span)
164 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700165}
166
David Tolnay360efd22018-01-04 23:35:26 -0800167impl LitByteStr {
168 pub fn new(value: &[u8], span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700169 let mut token = Literal::byte_string(value);
170 token.set_span(span);
171 LitByteStr { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800172 }
173
174 pub fn value(&self) -> Vec<u8> {
175 value::parse_lit_byte_str(&self.token.to_string())
176 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700177
178 pub fn span(&self) -> Span {
179 self.token.span()
180 }
181
182 pub fn set_span(&mut self, span: Span) {
183 self.token.set_span(span)
184 }
David Tolnay360efd22018-01-04 23:35:26 -0800185}
186
187impl LitByte {
188 pub fn new(value: u8, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700189 let mut token = Literal::u8_suffixed(value);
190 token.set_span(span);
191 LitByte { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800192 }
193
194 pub fn value(&self) -> u8 {
195 value::parse_lit_byte(&self.token.to_string())
196 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700197
198 pub fn span(&self) -> Span {
199 self.token.span()
200 }
201
202 pub fn set_span(&mut self, span: Span) {
203 self.token.set_span(span)
204 }
David Tolnay360efd22018-01-04 23:35:26 -0800205}
206
207impl LitChar {
208 pub fn new(value: char, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700209 let mut token = Literal::character(value);
210 token.set_span(span);
211 LitChar { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800212 }
213
214 pub fn value(&self) -> char {
215 value::parse_lit_char(&self.token.to_string())
216 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700217
218 pub fn span(&self) -> Span {
219 self.token.span()
220 }
221
222 pub fn set_span(&mut self, span: Span) {
223 self.token.set_span(span)
224 }
David Tolnay360efd22018-01-04 23:35:26 -0800225}
226
227impl LitInt {
228 pub fn new(value: u64, suffix: IntSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700229 let mut token = match suffix {
230 IntSuffix::Isize => Literal::isize_suffixed(value as isize),
231 IntSuffix::I8 => Literal::i8_suffixed(value as i8),
232 IntSuffix::I16 => Literal::i16_suffixed(value as i16),
233 IntSuffix::I32 => Literal::i32_suffixed(value as i32),
234 IntSuffix::I64 => Literal::i64_suffixed(value as i64),
235 IntSuffix::I128 => value::to_literal(&format!("{}i128", value)),
236 IntSuffix::Usize => Literal::usize_suffixed(value as usize),
237 IntSuffix::U8 => Literal::u8_suffixed(value as u8),
238 IntSuffix::U16 => Literal::u16_suffixed(value as u16),
239 IntSuffix::U32 => Literal::u32_suffixed(value as u32),
240 IntSuffix::U64 => Literal::u64_suffixed(value),
241 IntSuffix::U128 => value::to_literal(&format!("{}u128", value)),
242 IntSuffix::None => Literal::u64_unsuffixed(value),
243 };
244 token.set_span(span);
245 LitInt { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800246 }
247
248 pub fn value(&self) -> u64 {
249 value::parse_lit_int(&self.token.to_string()).unwrap()
250 }
251
252 pub fn suffix(&self) -> IntSuffix {
253 let value = self.token.to_string();
254 for (s, suffix) in vec![
255 ("i8", IntSuffix::I8),
256 ("i16", IntSuffix::I16),
257 ("i32", IntSuffix::I32),
258 ("i64", IntSuffix::I64),
259 ("i128", IntSuffix::I128),
260 ("isize", IntSuffix::Isize),
261 ("u8", IntSuffix::U8),
262 ("u16", IntSuffix::U16),
263 ("u32", IntSuffix::U32),
264 ("u64", IntSuffix::U64),
265 ("u128", IntSuffix::U128),
266 ("usize", IntSuffix::Usize),
267 ] {
268 if value.ends_with(s) {
269 return suffix;
270 }
271 }
272 IntSuffix::None
273 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700274
275 pub fn span(&self) -> Span {
276 self.token.span()
277 }
278
279 pub fn set_span(&mut self, span: Span) {
280 self.token.set_span(span)
281 }
David Tolnay360efd22018-01-04 23:35:26 -0800282}
283
284impl LitFloat {
285 pub fn new(value: f64, suffix: FloatSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700286 let mut token = match suffix {
287 FloatSuffix::F32 => Literal::f32_suffixed(value as f32),
288 FloatSuffix::F64 => Literal::f64_suffixed(value),
289 FloatSuffix::None => Literal::f64_unsuffixed(value),
290 };
291 token.set_span(span);
292 LitFloat { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800293 }
294
295 pub fn value(&self) -> f64 {
296 value::parse_lit_float(&self.token.to_string())
297 }
298
299 pub fn suffix(&self) -> FloatSuffix {
300 let value = self.token.to_string();
David Tolnay61037c62018-01-05 16:21:03 -0800301 for (s, suffix) in vec![("f32", FloatSuffix::F32), ("f64", FloatSuffix::F64)] {
David Tolnay360efd22018-01-04 23:35:26 -0800302 if value.ends_with(s) {
303 return suffix;
304 }
305 }
306 FloatSuffix::None
307 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700308
309 pub fn span(&self) -> Span {
310 self.token.span()
311 }
312
313 pub fn set_span(&mut self, span: Span) {
314 self.token.set_span(span)
315 }
David Tolnay360efd22018-01-04 23:35:26 -0800316}
317
318macro_rules! lit_extra_traits {
319 ($ty:ident, $field:ident) => {
320 #[cfg(feature = "extra-traits")]
321 impl Eq for $ty {}
322
323 #[cfg(feature = "extra-traits")]
324 impl PartialEq for $ty {
325 fn eq(&self, other: &Self) -> bool {
326 self.$field.to_string() == other.$field.to_string()
327 }
328 }
329
330 #[cfg(feature = "extra-traits")]
331 impl Hash for $ty {
332 fn hash<H>(&self, state: &mut H)
333 where
334 H: Hasher,
335 {
336 self.$field.to_string().hash(state);
337 }
David Tolnay9c76bcb2017-12-26 23:14:59 -0500338 }
Alex Crichton62a0a592017-05-22 13:58:53 -0700339 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700340}
341
Alex Crichton9a4dca22018-03-28 06:32:19 -0700342impl LitVerbatim {
343 pub fn span(&self) -> Span {
344 self.token.span()
345 }
346
347 pub fn set_span(&mut self, span: Span) {
348 self.token.set_span(span)
349 }
350}
351
David Tolnay360efd22018-01-04 23:35:26 -0800352lit_extra_traits!(LitStr, token);
353lit_extra_traits!(LitByteStr, token);
354lit_extra_traits!(LitByte, token);
355lit_extra_traits!(LitChar, token);
356lit_extra_traits!(LitInt, token);
357lit_extra_traits!(LitFloat, token);
358lit_extra_traits!(LitBool, value);
359lit_extra_traits!(LitVerbatim, token);
360
361ast_enum! {
David Tolnay05658502018-01-07 09:56:37 -0800362 /// The style of a string literal, either plain quoted or a raw string like
David Tolnayabf5c2e2018-01-06 23:30:04 -0800363 /// `r##"data"##`.
David Tolnay461d98e2018-01-07 11:07:19 -0800364 ///
365 /// *This type is available if Syn is built with the `"derive"` or `"full"`
366 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800367 pub enum StrStyle #no_visit {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800368 /// An ordinary string like `"data"`.
David Tolnay360efd22018-01-04 23:35:26 -0800369 Cooked,
David Tolnayabf5c2e2018-01-06 23:30:04 -0800370 /// A raw string like `r##"data"##`.
David Tolnay360efd22018-01-04 23:35:26 -0800371 ///
372 /// The unsigned integer is the number of `#` symbols used.
373 Raw(usize),
Alex Crichton62a0a592017-05-22 13:58:53 -0700374 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700375}
376
David Tolnay360efd22018-01-04 23:35:26 -0800377ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800378 /// The suffix on an integer literal if any, like the `u8` in `127u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800379 ///
380 /// *This type is available if Syn is built with the `"derive"` or `"full"`
381 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800382 pub enum IntSuffix #no_visit {
383 I8,
384 I16,
385 I32,
386 I64,
387 I128,
388 Isize,
389 U8,
390 U16,
391 U32,
392 U64,
393 U128,
394 Usize,
395 None,
Pascal Hertleif36342c52016-10-19 10:31:42 +0200396 }
397}
398
David Tolnay360efd22018-01-04 23:35:26 -0800399ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800400 /// The suffix on a floating point literal if any, like the `f32` in
401 /// `1.0f32`.
David Tolnay461d98e2018-01-07 11:07:19 -0800402 ///
403 /// *This type is available if Syn is built with the `"derive"` or `"full"`
404 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800405 pub enum FloatSuffix #no_visit {
406 F32,
407 F64,
408 None,
Alex Crichton2e0229c2017-05-23 09:34:50 -0700409 }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800410}
411
412#[cfg(feature = "parsing")]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700413pub mod parsing {
414 use super::*;
David Tolnayc5ab8c62017-12-26 16:43:39 -0500415 use synom::Synom;
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 Tolnayf4bbbd92016-09-23 14:41:55 -0700419
Alex Crichton954046c2017-05-30 21:49:42 -0700420 impl Synom for Lit {
Michael Layzell92639a52017-06-01 00:07:44 -0400421 fn parse(input: Cursor) -> PResult<Self> {
Michael Layzell589a8f42017-06-02 19:47:01 -0400422 match input.literal() {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700423 Some((lit, rest)) => {
David Tolnay7037c9b2018-01-23 09:34:09 -0800424 if lit.to_string().starts_with('/') {
425 // Doc comment literal which is not a Syn literal
426 parse_error()
427 } else {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700428 Ok((Lit::new(lit), rest))
David Tolnay7037c9b2018-01-23 09:34:09 -0800429 }
430 }
David Tolnay73c98de2017-12-31 15:56:56 -0500431 _ => match input.term() {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700432 Some((term, rest)) => Ok((
David Tolnay360efd22018-01-04 23:35:26 -0800433 Lit::Bool(LitBool {
434 value: if term.as_str() == "true" {
435 true
436 } else if term.as_str() == "false" {
437 false
438 } else {
439 return parse_error();
David Tolnay51382052017-12-27 13:46:21 -0500440 },
Alex Crichton9a4dca22018-03-28 06:32:19 -0700441 span: term.span(),
David Tolnay360efd22018-01-04 23:35:26 -0800442 }),
443 rest,
444 )),
Michael Layzell589a8f42017-06-02 19:47:01 -0400445 _ => parse_error(),
David Tolnay51382052017-12-27 13:46:21 -0500446 },
Michael Layzell589a8f42017-06-02 19:47:01 -0400447 }
David Tolnayfa0edf22016-09-23 22:58:24 -0700448 }
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800449
450 fn description() -> Option<&'static str> {
451 Some("literal")
452 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700453 }
David Tolnay360efd22018-01-04 23:35:26 -0800454
455 impl_synom!(LitStr "string literal" switch!(
456 syn!(Lit),
457 Lit::Str(lit) => value!(lit)
458 |
459 _ => reject!()
460 ));
461
462 impl_synom!(LitByteStr "byte string literal" switch!(
463 syn!(Lit),
464 Lit::ByteStr(lit) => value!(lit)
465 |
466 _ => reject!()
467 ));
468
469 impl_synom!(LitByte "byte literal" switch!(
470 syn!(Lit),
471 Lit::Byte(lit) => value!(lit)
472 |
473 _ => reject!()
474 ));
475
476 impl_synom!(LitChar "character literal" switch!(
477 syn!(Lit),
478 Lit::Char(lit) => value!(lit)
479 |
480 _ => reject!()
481 ));
482
483 impl_synom!(LitInt "integer literal" switch!(
484 syn!(Lit),
485 Lit::Int(lit) => value!(lit)
486 |
487 _ => reject!()
488 ));
489
490 impl_synom!(LitFloat "floating point literal" switch!(
491 syn!(Lit),
492 Lit::Float(lit) => value!(lit)
493 |
494 _ => reject!()
495 ));
496
497 impl_synom!(LitBool "boolean literal" switch!(
498 syn!(Lit),
499 Lit::Bool(lit) => value!(lit)
500 |
501 _ => reject!()
502 ));
David Tolnayf4bbbd92016-09-23 14:41:55 -0700503}
504
505#[cfg(feature = "printing")]
506mod printing {
507 use super::*;
David Tolnay51382052017-12-27 13:46:21 -0500508 use quote::{ToTokens, Tokens};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700509
David Tolnay360efd22018-01-04 23:35:26 -0800510 impl ToTokens for LitStr {
David Tolnayf4bbbd92016-09-23 14:41:55 -0700511 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700512 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800513 }
514 }
515
516 impl ToTokens for LitByteStr {
517 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700518 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800519 }
520 }
521
522 impl ToTokens for LitByte {
523 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700524 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800525 }
526 }
527
528 impl ToTokens for LitChar {
529 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700530 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800531 }
532 }
533
534 impl ToTokens for LitInt {
535 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700536 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800537 }
538 }
539
540 impl ToTokens for LitFloat {
541 fn to_tokens(&self, tokens: &mut Tokens) {
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 LitBool {
547 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700548 let s = if self.value { "true" } else { "false" };
549 tokens.append(Term::new(s, self.span));
David Tolnay360efd22018-01-04 23:35:26 -0800550 }
551 }
552
553 impl ToTokens for LitVerbatim {
554 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700555 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800556 }
557 }
558}
559
560mod value {
561 use super::*;
562 use std::char;
563 use std::ops::{Index, RangeFrom};
564 use proc_macro2::TokenStream;
565
David Tolnay7d1d1282018-01-06 16:10:51 -0800566 impl Lit {
David Tolnay780292d2018-01-22 23:26:44 -0800567 /// Interpret a Syn literal from a proc-macro2 literal.
568 ///
569 /// Not all proc-macro2 literals are valid Syn literals. In particular,
570 /// doc comments are considered by proc-macro2 to be literals but in Syn
571 /// they are [`Attribute`].
572 ///
573 /// [`Attribute`]: struct.Attribute.html
574 ///
575 /// # Panics
576 ///
577 /// Panics if the input is a doc comment literal.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700578 pub fn new(token: Literal) -> Self {
David Tolnay7d1d1282018-01-06 16:10:51 -0800579 let value = token.to_string();
580
581 match value::byte(&value, 0) {
582 b'"' | b'r' => {
583 return Lit::Str(LitStr {
584 token: token,
David Tolnay7d1d1282018-01-06 16:10:51 -0800585 })
586 }
587 b'b' => match value::byte(&value, 1) {
588 b'"' | b'r' => {
589 return Lit::ByteStr(LitByteStr {
590 token: token,
David Tolnay7d1d1282018-01-06 16:10:51 -0800591 })
592 }
593 b'\'' => {
594 return Lit::Byte(LitByte {
595 token: token,
David Tolnay7d1d1282018-01-06 16:10:51 -0800596 })
597 }
598 _ => {}
599 },
600 b'\'' => {
601 return Lit::Char(LitChar {
602 token: token,
David Tolnay7d1d1282018-01-06 16:10:51 -0800603 })
604 }
605 b'0'...b'9' => if number_is_int(&value) {
606 return Lit::Int(LitInt {
607 token: token,
David Tolnay7d1d1282018-01-06 16:10:51 -0800608 });
609 } else if number_is_float(&value) {
610 return Lit::Float(LitFloat {
611 token: token,
David Tolnay7d1d1282018-01-06 16:10:51 -0800612 });
613 } else {
614 // number overflow
615 return Lit::Verbatim(LitVerbatim {
616 token: token,
David Tolnay7d1d1282018-01-06 16:10:51 -0800617 });
618 },
619 _ => if value == "true" || value == "false" {
620 return Lit::Bool(LitBool {
621 value: value == "true",
Alex Crichton9a4dca22018-03-28 06:32:19 -0700622 span: token.span(),
David Tolnay7d1d1282018-01-06 16:10:51 -0800623 });
624 },
625 }
626
627 panic!("Unrecognized literal: {}", value);
628 }
629 }
630
631 fn number_is_int(value: &str) -> bool {
632 if number_is_float(value) {
633 false
634 } else {
635 value::parse_lit_int(value).is_some()
636 }
637 }
638
639 fn number_is_float(value: &str) -> bool {
640 if value.contains('.') {
641 true
642 } else if value.starts_with("0x") || value.ends_with("size") {
643 false
644 } else {
645 value.contains('e') || value.contains('E')
646 }
647 }
648
David Tolnay360efd22018-01-04 23:35:26 -0800649 /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
650 /// past the end of the input buffer.
651 pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
652 let s = s.as_ref();
653 if idx < s.len() {
654 s[idx]
655 } else {
656 0
657 }
658 }
659
660 fn next_chr(s: &str) -> char {
661 s.chars().next().unwrap_or('\0')
662 }
663
664 pub fn parse_lit_str(s: &str) -> String {
665 match byte(s, 0) {
666 b'"' => parse_lit_str_cooked(s),
667 b'r' => parse_lit_str_raw(s),
668 _ => unreachable!(),
669 }
670 }
671
David Tolnay76ebcdd2018-01-05 17:07:26 -0800672 // Clippy false positive
673 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
674 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800675 fn parse_lit_str_cooked(mut s: &str) -> String {
676 assert_eq!(byte(s, 0), b'"');
677 s = &s[1..];
678
679 let mut out = String::new();
680 'outer: loop {
681 let ch = match byte(s, 0) {
682 b'"' => break,
683 b'\\' => {
684 let b = byte(s, 1);
685 s = &s[2..];
686 match b {
687 b'x' => {
688 let (byte, rest) = backslash_x(s);
689 s = rest;
690 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800691 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800692 }
693 b'u' => {
David Tolnay76ebcdd2018-01-05 17:07:26 -0800694 let (chr, rest) = backslash_u(s);
David Tolnay360efd22018-01-04 23:35:26 -0800695 s = rest;
696 chr
697 }
698 b'n' => '\n',
699 b'r' => '\r',
700 b't' => '\t',
701 b'\\' => '\\',
702 b'0' => '\0',
703 b'\'' => '\'',
704 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800705 b'\r' | b'\n' => loop {
706 let ch = next_chr(s);
707 if ch.is_whitespace() {
708 s = &s[ch.len_utf8()..];
709 } else {
710 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800711 }
David Tolnay61037c62018-01-05 16:21:03 -0800712 },
713 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800714 }
715 }
716 b'\r' => {
717 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
718 s = &s[2..];
719 '\n'
720 }
721 _ => {
722 let ch = next_chr(s);
723 s = &s[ch.len_utf8()..];
724 ch
725 }
726 };
727 out.push(ch);
728 }
729
730 assert_eq!(s, "\"");
731 out
732 }
733
734 fn parse_lit_str_raw(mut s: &str) -> String {
735 assert_eq!(byte(s, 0), b'r');
736 s = &s[1..];
737
738 let mut pounds = 0;
739 while byte(s, pounds) == b'#' {
740 pounds += 1;
741 }
742 assert_eq!(byte(s, pounds), b'"');
743 assert_eq!(byte(s, s.len() - pounds - 1), b'"');
744 for end in s[s.len() - pounds..].bytes() {
745 assert_eq!(end, b'#');
746 }
747
748 s[pounds + 1..s.len() - pounds - 1].to_owned()
749 }
750
751 pub fn parse_lit_byte_str(s: &str) -> Vec<u8> {
752 assert_eq!(byte(s, 0), b'b');
753 match byte(s, 1) {
754 b'"' => parse_lit_byte_str_cooked(s),
755 b'r' => parse_lit_byte_str_raw(s),
756 _ => unreachable!(),
757 }
758 }
759
David Tolnay76ebcdd2018-01-05 17:07:26 -0800760 // Clippy false positive
761 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
762 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800763 fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> {
764 assert_eq!(byte(s, 0), b'b');
765 assert_eq!(byte(s, 1), b'"');
766 s = &s[2..];
767
768 // We're going to want to have slices which don't respect codepoint boundaries.
769 let mut s = s.as_bytes();
770
771 let mut out = Vec::new();
772 'outer: loop {
773 let byte = match byte(s, 0) {
774 b'"' => break,
775 b'\\' => {
776 let b = byte(s, 1);
777 s = &s[2..];
778 match b {
779 b'x' => {
780 let (b, rest) = backslash_x(s);
781 s = rest;
782 b
783 }
784 b'n' => b'\n',
785 b'r' => b'\r',
786 b't' => b'\t',
787 b'\\' => b'\\',
788 b'0' => b'\0',
789 b'\'' => b'\'',
790 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800791 b'\r' | b'\n' => loop {
792 let byte = byte(s, 0);
David Tolnay76ebcdd2018-01-05 17:07:26 -0800793 let ch = char::from_u32(u32::from(byte)).unwrap();
David Tolnay61037c62018-01-05 16:21:03 -0800794 if ch.is_whitespace() {
795 s = &s[1..];
796 } else {
797 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800798 }
David Tolnay61037c62018-01-05 16:21:03 -0800799 },
800 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800801 }
802 }
803 b'\r' => {
804 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
805 s = &s[2..];
806 b'\n'
807 }
808 b => {
809 s = &s[1..];
810 b
811 }
812 };
813 out.push(byte);
814 }
815
816 assert_eq!(s, b"\"");
817 out
818 }
819
820 fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> {
821 assert_eq!(byte(s, 0), b'b');
822 parse_lit_str_raw(&s[1..]).into_bytes()
823 }
824
825 pub fn parse_lit_byte(s: &str) -> u8 {
826 assert_eq!(byte(s, 0), b'b');
827 assert_eq!(byte(s, 1), b'\'');
828
829 // We're going to want to have slices which don't respect codepoint boundaries.
830 let mut s = s[2..].as_bytes();
831
832 let b = match byte(s, 0) {
833 b'\\' => {
834 let b = byte(s, 1);
835 s = &s[2..];
836 match b {
837 b'x' => {
838 let (b, rest) = backslash_x(s);
839 s = rest;
840 b
841 }
842 b'n' => b'\n',
843 b'r' => b'\r',
844 b't' => b'\t',
845 b'\\' => b'\\',
846 b'0' => b'\0',
847 b'\'' => b'\'',
848 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800849 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800850 }
851 }
852 b => {
853 s = &s[1..];
854 b
855 }
856 };
857
858 assert_eq!(byte(s, 0), b'\'');
859 b
860 }
861
862 pub fn parse_lit_char(mut s: &str) -> char {
863 assert_eq!(byte(s, 0), b'\'');
864 s = &s[1..];
865
866 let ch = match byte(s, 0) {
867 b'\\' => {
868 let b = byte(s, 1);
869 s = &s[2..];
870 match b {
871 b'x' => {
872 let (byte, rest) = backslash_x(s);
873 s = rest;
874 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800875 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800876 }
877 b'u' => {
878 let (chr, rest) = backslash_u(s);
879 s = rest;
880 chr
881 }
882 b'n' => '\n',
883 b'r' => '\r',
884 b't' => '\t',
885 b'\\' => '\\',
886 b'0' => '\0',
887 b'\'' => '\'',
888 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800889 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800890 }
891 }
892 _ => {
893 let ch = next_chr(s);
894 s = &s[ch.len_utf8()..];
895 ch
896 }
897 };
898 assert_eq!(s, "\'", "Expected end of char literal");
899 ch
900 }
901
902 fn backslash_x<S>(s: &S) -> (u8, &S)
David Tolnay61037c62018-01-05 16:21:03 -0800903 where
904 S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
David Tolnay360efd22018-01-04 23:35:26 -0800905 {
906 let mut ch = 0;
907 let b0 = byte(s, 0);
908 let b1 = byte(s, 1);
909 ch += 0x10 * match b0 {
910 b'0'...b'9' => b0 - b'0',
911 b'a'...b'f' => 10 + (b0 - b'a'),
912 b'A'...b'F' => 10 + (b0 - b'A'),
913 _ => panic!("unexpected non-hex character after \\x"),
914 };
David Tolnay76ebcdd2018-01-05 17:07:26 -0800915 ch += match b1 {
David Tolnay360efd22018-01-04 23:35:26 -0800916 b'0'...b'9' => b1 - b'0',
917 b'a'...b'f' => 10 + (b1 - b'a'),
918 b'A'...b'F' => 10 + (b1 - b'A'),
919 _ => panic!("unexpected non-hex character after \\x"),
920 };
921 (ch, &s[2..])
922 }
923
924 fn backslash_u(mut s: &str) -> (char, &str) {
925 if byte(s, 0) != b'{' {
926 panic!("expected {{ after \\u");
927 }
928 s = &s[1..];
929
930 let mut ch = 0;
931 for _ in 0..6 {
932 let b = byte(s, 0);
933 match b {
934 b'0'...b'9' => {
935 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800936 ch += u32::from(b - b'0');
David Tolnay360efd22018-01-04 23:35:26 -0800937 s = &s[1..];
938 }
939 b'a'...b'f' => {
940 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800941 ch += u32::from(10 + b - b'a');
David Tolnay360efd22018-01-04 23:35:26 -0800942 s = &s[1..];
943 }
944 b'A'...b'F' => {
945 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800946 ch += u32::from(10 + b - b'A');
David Tolnay360efd22018-01-04 23:35:26 -0800947 s = &s[1..];
948 }
949 b'}' => break,
950 _ => panic!("unexpected non-hex character after \\u"),
951 }
952 }
953 assert!(byte(s, 0) == b'}');
954 s = &s[1..];
955
956 if let Some(ch) = char::from_u32(ch) {
957 (ch, s)
958 } else {
959 panic!("character code {:x} is not a valid unicode character", ch);
960 }
961 }
962
963 pub fn parse_lit_int(mut s: &str) -> Option<u64> {
964 let base = match (byte(s, 0), byte(s, 1)) {
965 (b'0', b'x') => {
966 s = &s[2..];
967 16
968 }
969 (b'0', b'o') => {
970 s = &s[2..];
971 8
972 }
973 (b'0', b'b') => {
974 s = &s[2..];
975 2
976 }
977 (b'0'...b'9', _) => 10,
978 _ => unreachable!(),
979 };
980
981 let mut value = 0u64;
982 loop {
983 let b = byte(s, 0);
984 let digit = match b {
David Tolnay76ebcdd2018-01-05 17:07:26 -0800985 b'0'...b'9' => u64::from(b - b'0'),
986 b'a'...b'f' if base > 10 => 10 + u64::from(b - b'a'),
987 b'A'...b'F' if base > 10 => 10 + u64::from(b - b'A'),
David Tolnay360efd22018-01-04 23:35:26 -0800988 b'_' => {
989 s = &s[1..];
990 continue;
991 }
992 // NOTE: Looking at a floating point literal, we don't want to
993 // consider these integers.
994 b'.' if base == 10 => return None,
995 b'e' | b'E' if base == 10 => return None,
996 _ => break,
997 };
998
999 if digit >= base {
1000 panic!("Unexpected digit {:x} out of base range", digit);
1001 }
1002
1003 value = match value.checked_mul(base) {
1004 Some(value) => value,
1005 None => return None,
1006 };
1007 value = match value.checked_add(digit) {
1008 Some(value) => value,
1009 None => return None,
1010 };
1011 s = &s[1..];
1012 }
1013
1014 Some(value)
1015 }
1016
1017 pub fn parse_lit_float(input: &str) -> f64 {
1018 // Rust's floating point literals are very similar to the ones parsed by
1019 // the standard library, except that rust's literals can contain
1020 // ignorable underscores. Let's remove those underscores.
1021 let mut bytes = input.to_owned().into_bytes();
1022 let mut write = 0;
1023 for read in 0..bytes.len() {
1024 if bytes[read] == b'_' {
1025 continue; // Don't increase write
David Tolnay76ebcdd2018-01-05 17:07:26 -08001026 }
1027 if write != read {
David Tolnay360efd22018-01-04 23:35:26 -08001028 let x = bytes[read];
1029 bytes[write] = x;
1030 }
1031 write += 1;
1032 }
1033 bytes.truncate(write);
1034 let input = String::from_utf8(bytes).unwrap();
David Tolnay76ebcdd2018-01-05 17:07:26 -08001035 let end = input.find('f').unwrap_or_else(|| input.len());
David Tolnay360efd22018-01-04 23:35:26 -08001036 input[..end].parse().unwrap()
1037 }
1038
1039 pub fn to_literal(s: &str) -> Literal {
1040 let stream = s.parse::<TokenStream>().unwrap();
Alex Crichton9a4dca22018-03-28 06:32:19 -07001041 match stream.into_iter().next().unwrap() {
1042 TokenTree::Literal(l) => l,
David Tolnay360efd22018-01-04 23:35:26 -08001043 _ => unreachable!(),
David Tolnayf17fd2f2016-10-07 23:38:08 -07001044 }
1045 }
David Tolnayf4bbbd92016-09-23 14:41:55 -07001046}