]> git.proxmox.com Git - rustc.git/blame - vendor/syn/src/lit.rs
New upstream version 1.48.0~beta.8+dfsg1
[rustc.git] / vendor / syn / src / lit.rs
CommitLineData
e74abb32
XL
1use proc_macro2::{Literal, Span};
2use std::fmt::{self, Display};
3use std::str::{self, FromStr};
4
5#[cfg(feature = "printing")]
6use proc_macro2::Ident;
7
8#[cfg(feature = "parsing")]
9use proc_macro2::TokenStream;
10
11use proc_macro2::TokenTree;
12
13#[cfg(feature = "extra-traits")]
14use std::hash::{Hash, Hasher};
15
16#[cfg(feature = "parsing")]
17use crate::lookahead;
18#[cfg(feature = "parsing")]
19use crate::parse::{Parse, Parser};
20use crate::{Error, Result};
21
22ast_enum_of_structs! {
23 /// A Rust literal such as a string or integer or boolean.
24 ///
e74abb32
XL
25 /// # Syntax tree enum
26 ///
27 /// This type is a [syntax tree enum].
28 ///
29 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
30 //
31 // TODO: change syntax-tree-enum link to an intra rustdoc link, currently
32 // blocked on https://github.com/rust-lang/rust/issues/62833
1b1a35ee 33 pub enum Lit {
e74abb32
XL
34 /// A UTF-8 string literal: `"foo"`.
35 Str(LitStr),
36
37 /// A byte string literal: `b"foo"`.
38 ByteStr(LitByteStr),
39
40 /// A byte literal: `b'f'`.
41 Byte(LitByte),
42
43 /// A character literal: `'a'`.
44 Char(LitChar),
45
46 /// An integer literal: `1` or `1u16`.
47 Int(LitInt),
48
49 /// A floating point literal: `1f64` or `1.0e10f64`.
50 ///
51 /// Must be finite. May not be infinte or NaN.
52 Float(LitFloat),
53
54 /// A boolean literal: `true` or `false`.
55 Bool(LitBool),
56
57 /// A raw token literal not interpreted by Syn.
58 Verbatim(Literal),
59 }
60}
61
62ast_struct! {
63 /// A UTF-8 string literal: `"foo"`.
1b1a35ee 64 pub struct LitStr {
f035d41b 65 repr: Box<LitRepr>,
e74abb32
XL
66 }
67}
68
e74abb32
XL
69ast_struct! {
70 /// A byte string literal: `b"foo"`.
1b1a35ee 71 pub struct LitByteStr {
f035d41b 72 repr: Box<LitRepr>,
e74abb32
XL
73 }
74}
75
76ast_struct! {
77 /// A byte literal: `b'f'`.
1b1a35ee 78 pub struct LitByte {
f035d41b 79 repr: Box<LitRepr>,
e74abb32
XL
80 }
81}
82
83ast_struct! {
84 /// A character literal: `'a'`.
1b1a35ee 85 pub struct LitChar {
f035d41b 86 repr: Box<LitRepr>,
e74abb32
XL
87 }
88}
89
f035d41b
XL
90struct LitRepr {
91 token: Literal,
92 suffix: Box<str>,
93}
94
e74abb32
XL
95ast_struct! {
96 /// An integer literal: `1` or `1u16`.
1b1a35ee 97 pub struct LitInt {
e74abb32
XL
98 repr: Box<LitIntRepr>,
99 }
100}
101
e74abb32
XL
102struct LitIntRepr {
103 token: Literal,
104 digits: Box<str>,
105 suffix: Box<str>,
106}
107
108ast_struct! {
109 /// A floating point literal: `1f64` or `1.0e10f64`.
110 ///
111 /// Must be finite. May not be infinte or NaN.
1b1a35ee 112 pub struct LitFloat {
e74abb32
XL
113 repr: Box<LitFloatRepr>,
114 }
115}
116
e74abb32
XL
117struct LitFloatRepr {
118 token: Literal,
119 digits: Box<str>,
120 suffix: Box<str>,
121}
122
123ast_struct! {
124 /// A boolean literal: `true` or `false`.
1b1a35ee 125 pub struct LitBool {
e74abb32
XL
126 pub value: bool,
127 pub span: Span,
128 }
129}
130
e74abb32
XL
131impl LitStr {
132 pub fn new(value: &str, span: Span) -> Self {
f035d41b
XL
133 let mut token = Literal::string(value);
134 token.set_span(span);
e74abb32 135 LitStr {
f035d41b
XL
136 repr: Box::new(LitRepr {
137 token,
e74abb32
XL
138 suffix: Box::<str>::default(),
139 }),
140 }
141 }
142
143 pub fn value(&self) -> String {
f035d41b
XL
144 let repr = self.repr.token.to_string();
145 let (value, _suffix) = value::parse_lit_str(&repr);
e74abb32
XL
146 String::from(value)
147 }
148
149 /// Parse a syntax tree node from the content of this string literal.
150 ///
151 /// All spans in the syntax tree will point to the span of this `LitStr`.
152 ///
153 /// # Example
154 ///
155 /// ```
156 /// use proc_macro2::Span;
157 /// use syn::{Attribute, Error, Ident, Lit, Meta, MetaNameValue, Path, Result};
158 ///
159 /// // Parses the path from an attribute that looks like:
160 /// //
161 /// // #[path = "a::b::c"]
162 /// //
163 /// // or returns `None` if the input is some other attribute.
164 /// fn get_path(attr: &Attribute) -> Result<Option<Path>> {
165 /// if !attr.path.is_ident("path") {
166 /// return Ok(None);
167 /// }
168 ///
169 /// match attr.parse_meta()? {
170 /// Meta::NameValue(MetaNameValue { lit: Lit::Str(lit_str), .. }) => {
171 /// lit_str.parse().map(Some)
172 /// }
173 /// _ => {
174 /// let message = "expected #[path = \"...\"]";
175 /// Err(Error::new_spanned(attr, message))
176 /// }
177 /// }
178 /// }
179 /// ```
180 #[cfg(feature = "parsing")]
181 pub fn parse<T: Parse>(&self) -> Result<T> {
182 self.parse_with(T::parse)
183 }
184
185 /// Invoke parser on the content of this string literal.
186 ///
187 /// All spans in the syntax tree will point to the span of this `LitStr`.
188 ///
189 /// # Example
190 ///
191 /// ```
192 /// # use proc_macro2::Span;
193 /// # use syn::{LitStr, Result};
194 /// #
195 /// # fn main() -> Result<()> {
196 /// # let lit_str = LitStr::new("a::b::c", Span::call_site());
197 /// #
198 /// # const IGNORE: &str = stringify! {
199 /// let lit_str: LitStr = /* ... */;
200 /// # };
201 ///
202 /// // Parse a string literal like "a::b::c" into a Path, not allowing
203 /// // generic arguments on any of the path segments.
204 /// let basic_path = lit_str.parse_with(syn::Path::parse_mod_style)?;
205 /// #
206 /// # Ok(())
207 /// # }
208 /// ```
209 #[cfg(feature = "parsing")]
210 pub fn parse_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
211 use proc_macro2::Group;
212
213 // Token stream with every span replaced by the given one.
214 fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
215 stream
216 .into_iter()
217 .map(|token| respan_token_tree(token, span))
218 .collect()
219 }
220
221 // Token tree with every span replaced by the given one.
222 fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
223 match &mut token {
224 TokenTree::Group(g) => {
60c5eb7d 225 let stream = respan_token_stream(g.stream(), span);
e74abb32
XL
226 *g = Group::new(g.delimiter(), stream);
227 g.set_span(span);
228 }
229 other => other.set_span(span),
230 }
231 token
232 }
233
234 // Parse string literal into a token stream with every span equal to the
235 // original literal's span.
236 let mut tokens = crate::parse_str(&self.value())?;
237 tokens = respan_token_stream(tokens, self.span());
238
239 parser.parse2(tokens)
240 }
241
242 pub fn span(&self) -> Span {
243 self.repr.token.span()
244 }
245
246 pub fn set_span(&mut self, span: Span) {
247 self.repr.token.set_span(span)
248 }
249
250 pub fn suffix(&self) -> &str {
251 &self.repr.suffix
252 }
253}
254
255impl LitByteStr {
256 pub fn new(value: &[u8], span: Span) -> Self {
257 let mut token = Literal::byte_string(value);
258 token.set_span(span);
f035d41b
XL
259 LitByteStr {
260 repr: Box::new(LitRepr {
261 token,
262 suffix: Box::<str>::default(),
263 }),
264 }
e74abb32
XL
265 }
266
267 pub fn value(&self) -> Vec<u8> {
f035d41b
XL
268 let repr = self.repr.token.to_string();
269 let (value, _suffix) = value::parse_lit_byte_str(&repr);
270 value
e74abb32
XL
271 }
272
273 pub fn span(&self) -> Span {
f035d41b 274 self.repr.token.span()
e74abb32
XL
275 }
276
277 pub fn set_span(&mut self, span: Span) {
f035d41b
XL
278 self.repr.token.set_span(span)
279 }
280
281 pub fn suffix(&self) -> &str {
282 &self.repr.suffix
e74abb32
XL
283 }
284}
285
286impl LitByte {
287 pub fn new(value: u8, span: Span) -> Self {
288 let mut token = Literal::u8_suffixed(value);
289 token.set_span(span);
f035d41b
XL
290 LitByte {
291 repr: Box::new(LitRepr {
292 token,
293 suffix: Box::<str>::default(),
294 }),
295 }
e74abb32
XL
296 }
297
298 pub fn value(&self) -> u8 {
f035d41b
XL
299 let repr = self.repr.token.to_string();
300 let (value, _suffix) = value::parse_lit_byte(&repr);
301 value
e74abb32
XL
302 }
303
304 pub fn span(&self) -> Span {
f035d41b 305 self.repr.token.span()
e74abb32
XL
306 }
307
308 pub fn set_span(&mut self, span: Span) {
f035d41b
XL
309 self.repr.token.set_span(span)
310 }
311
312 pub fn suffix(&self) -> &str {
313 &self.repr.suffix
e74abb32
XL
314 }
315}
316
317impl LitChar {
318 pub fn new(value: char, span: Span) -> Self {
319 let mut token = Literal::character(value);
320 token.set_span(span);
f035d41b
XL
321 LitChar {
322 repr: Box::new(LitRepr {
323 token,
324 suffix: Box::<str>::default(),
325 }),
326 }
e74abb32
XL
327 }
328
329 pub fn value(&self) -> char {
f035d41b
XL
330 let repr = self.repr.token.to_string();
331 let (value, _suffix) = value::parse_lit_char(&repr);
332 value
e74abb32
XL
333 }
334
335 pub fn span(&self) -> Span {
f035d41b 336 self.repr.token.span()
e74abb32
XL
337 }
338
339 pub fn set_span(&mut self, span: Span) {
f035d41b
XL
340 self.repr.token.set_span(span)
341 }
342
343 pub fn suffix(&self) -> &str {
344 &self.repr.suffix
e74abb32
XL
345 }
346}
347
348impl LitInt {
349 pub fn new(repr: &str, span: Span) -> Self {
f035d41b
XL
350 let (digits, suffix) = match value::parse_lit_int(repr) {
351 Some(parse) => parse,
352 None => panic!("Not an integer literal: `{}`", repr),
353 };
354
355 let mut token = match value::to_literal(repr, &digits, &suffix) {
356 Some(token) => token,
357 None => panic!("Unsupported integer literal: `{}`", repr),
358 };
359
360 token.set_span(span);
361 LitInt {
362 repr: Box::new(LitIntRepr {
363 token,
364 digits,
365 suffix,
366 }),
e74abb32
XL
367 }
368 }
369
370 pub fn base10_digits(&self) -> &str {
371 &self.repr.digits
372 }
373
374 /// Parses the literal into a selected number type.
375 ///
376 /// This is equivalent to `lit.base10_digits().parse()` except that the
377 /// resulting errors will be correctly spanned to point to the literal token
378 /// in the macro input.
379 ///
380 /// ```
381 /// use syn::LitInt;
382 /// use syn::parse::{Parse, ParseStream, Result};
383 ///
384 /// struct Port {
385 /// value: u16,
386 /// }
387 ///
388 /// impl Parse for Port {
389 /// fn parse(input: ParseStream) -> Result<Self> {
390 /// let lit: LitInt = input.parse()?;
391 /// let value = lit.base10_parse::<u16>()?;
392 /// Ok(Port { value })
393 /// }
394 /// }
395 /// ```
396 pub fn base10_parse<N>(&self) -> Result<N>
397 where
398 N: FromStr,
399 N::Err: Display,
400 {
401 self.base10_digits()
402 .parse()
403 .map_err(|err| Error::new(self.span(), err))
404 }
405
406 pub fn suffix(&self) -> &str {
407 &self.repr.suffix
408 }
409
410 pub fn span(&self) -> Span {
411 self.repr.token.span()
412 }
413
414 pub fn set_span(&mut self, span: Span) {
415 self.repr.token.set_span(span)
416 }
417}
418
419impl From<Literal> for LitInt {
420 fn from(token: Literal) -> Self {
421 let repr = token.to_string();
422 if let Some((digits, suffix)) = value::parse_lit_int(&repr) {
423 LitInt {
424 repr: Box::new(LitIntRepr {
425 token,
426 digits,
427 suffix,
428 }),
429 }
430 } else {
431 panic!("Not an integer literal: `{}`", repr);
432 }
433 }
434}
435
436impl Display for LitInt {
437 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
438 self.repr.token.fmt(formatter)
439 }
440}
441
442impl LitFloat {
443 pub fn new(repr: &str, span: Span) -> Self {
f035d41b
XL
444 let (digits, suffix) = match value::parse_lit_float(repr) {
445 Some(parse) => parse,
446 None => panic!("Not a float literal: `{}`", repr),
447 };
448
449 let mut token = match value::to_literal(repr, &digits, &suffix) {
450 Some(token) => token,
451 None => panic!("Unsupported float literal: `{}`", repr),
452 };
453
454 token.set_span(span);
455 LitFloat {
456 repr: Box::new(LitFloatRepr {
457 token,
458 digits,
459 suffix,
460 }),
e74abb32
XL
461 }
462 }
463
464 pub fn base10_digits(&self) -> &str {
465 &self.repr.digits
466 }
467
468 pub fn base10_parse<N>(&self) -> Result<N>
469 where
470 N: FromStr,
471 N::Err: Display,
472 {
473 self.base10_digits()
474 .parse()
475 .map_err(|err| Error::new(self.span(), err))
476 }
477
478 pub fn suffix(&self) -> &str {
479 &self.repr.suffix
480 }
481
482 pub fn span(&self) -> Span {
483 self.repr.token.span()
484 }
485
486 pub fn set_span(&mut self, span: Span) {
487 self.repr.token.set_span(span)
488 }
489}
490
491impl From<Literal> for LitFloat {
492 fn from(token: Literal) -> Self {
493 let repr = token.to_string();
494 if let Some((digits, suffix)) = value::parse_lit_float(&repr) {
495 LitFloat {
496 repr: Box::new(LitFloatRepr {
497 token,
498 digits,
499 suffix,
500 }),
501 }
502 } else {
503 panic!("Not a float literal: `{}`", repr);
504 }
505 }
506}
507
508impl Display for LitFloat {
509 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
510 self.repr.token.fmt(formatter)
511 }
512}
513
514#[cfg(feature = "extra-traits")]
515mod debug_impls {
516 use super::*;
517 use std::fmt::{self, Debug};
518
519 impl Debug for LitStr {
520 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
521 formatter
522 .debug_struct("LitStr")
523 .field("token", &format_args!("{}", self.repr.token))
524 .finish()
525 }
526 }
527
528 impl Debug for LitByteStr {
529 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
530 formatter
531 .debug_struct("LitByteStr")
f035d41b 532 .field("token", &format_args!("{}", self.repr.token))
e74abb32
XL
533 .finish()
534 }
535 }
536
537 impl Debug for LitByte {
538 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
539 formatter
540 .debug_struct("LitByte")
f035d41b 541 .field("token", &format_args!("{}", self.repr.token))
e74abb32
XL
542 .finish()
543 }
544 }
545
546 impl Debug for LitChar {
547 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
548 formatter
549 .debug_struct("LitChar")
f035d41b 550 .field("token", &format_args!("{}", self.repr.token))
e74abb32
XL
551 .finish()
552 }
553 }
554
555 impl Debug for LitInt {
556 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
557 formatter
558 .debug_struct("LitInt")
559 .field("token", &format_args!("{}", self.repr.token))
560 .finish()
561 }
562 }
563
564 impl Debug for LitFloat {
565 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
566 formatter
567 .debug_struct("LitFloat")
568 .field("token", &format_args!("{}", self.repr.token))
569 .finish()
570 }
571 }
572
573 impl Debug for LitBool {
574 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
575 formatter
576 .debug_struct("LitBool")
577 .field("value", &self.value)
578 .finish()
579 }
580 }
581}
582
1b1a35ee
XL
583#[cfg(feature = "clone-impls")]
584impl Clone for LitRepr {
585 fn clone(&self) -> Self {
586 LitRepr {
587 token: self.token.clone(),
588 suffix: self.suffix.clone(),
589 }
590 }
591}
592
593#[cfg(feature = "clone-impls")]
594impl Clone for LitIntRepr {
595 fn clone(&self) -> Self {
596 LitIntRepr {
597 token: self.token.clone(),
598 digits: self.digits.clone(),
599 suffix: self.suffix.clone(),
600 }
601 }
602}
603
604#[cfg(feature = "clone-impls")]
605impl Clone for LitFloatRepr {
606 fn clone(&self) -> Self {
607 LitFloatRepr {
608 token: self.token.clone(),
609 digits: self.digits.clone(),
610 suffix: self.suffix.clone(),
611 }
612 }
613}
614
e74abb32 615macro_rules! lit_extra_traits {
1b1a35ee
XL
616 ($ty:ident) => {
617 #[cfg(feature = "clone-impls")]
618 impl Clone for $ty {
619 fn clone(&self) -> Self {
620 $ty {
621 repr: self.repr.clone(),
622 }
623 }
624 }
e74abb32
XL
625
626 #[cfg(feature = "extra-traits")]
627 impl PartialEq for $ty {
628 fn eq(&self, other: &Self) -> bool {
1b1a35ee 629 self.repr.token.to_string() == other.repr.token.to_string()
e74abb32
XL
630 }
631 }
632
633 #[cfg(feature = "extra-traits")]
634 impl Hash for $ty {
635 fn hash<H>(&self, state: &mut H)
636 where
637 H: Hasher,
638 {
1b1a35ee 639 self.repr.token.to_string().hash(state);
e74abb32
XL
640 }
641 }
642
643 #[cfg(feature = "parsing")]
644 #[doc(hidden)]
645 #[allow(non_snake_case)]
646 pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
647 match marker {}
648 }
649 };
650}
651
1b1a35ee
XL
652lit_extra_traits!(LitStr);
653lit_extra_traits!(LitByteStr);
654lit_extra_traits!(LitByte);
655lit_extra_traits!(LitChar);
656lit_extra_traits!(LitInt);
657lit_extra_traits!(LitFloat);
658
659#[cfg(feature = "parsing")]
660#[doc(hidden)]
661#[allow(non_snake_case)]
662pub fn LitBool(marker: lookahead::TokenMarker) -> LitBool {
663 match marker {}
664}
e74abb32
XL
665
666ast_enum! {
667 /// The style of a string literal, either plain quoted or a raw string like
668 /// `r##"data"##`.
e74abb32
XL
669 pub enum StrStyle #no_visit {
670 /// An ordinary string like `"data"`.
671 Cooked,
672 /// A raw string like `r##"data"##`.
673 ///
674 /// The unsigned integer is the number of `#` symbols used.
675 Raw(usize),
676 }
677}
678
679#[cfg(feature = "parsing")]
680#[doc(hidden)]
681#[allow(non_snake_case)]
682pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
683 match marker {}
684}
685
686#[cfg(feature = "parsing")]
687pub mod parsing {
688 use super::*;
f035d41b 689 use crate::buffer::Cursor;
e74abb32 690 use crate::parse::{Parse, ParseStream, Result};
f035d41b 691 use proc_macro2::Punct;
e74abb32
XL
692
693 impl Parse for Lit {
694 fn parse(input: ParseStream) -> Result<Self> {
695 input.step(|cursor| {
696 if let Some((lit, rest)) = cursor.literal() {
697 return Ok((Lit::new(lit), rest));
698 }
f035d41b
XL
699
700 if let Some((ident, rest)) = cursor.ident() {
701 let value = ident == "true";
702 if value || ident == "false" {
703 let lit_bool = LitBool {
704 value,
705 span: ident.span(),
706 };
707 return Ok((Lit::Bool(lit_bool), rest));
708 }
709 }
710
711 if let Some((punct, rest)) = cursor.punct() {
712 if punct.as_char() == '-' {
713 if let Some((lit, rest)) = parse_negative_lit(punct, rest) {
714 return Ok((lit, rest));
715 }
716 }
e74abb32 717 }
f035d41b 718
e74abb32
XL
719 Err(cursor.error("expected literal"))
720 })
721 }
722 }
723
f035d41b
XL
724 fn parse_negative_lit(neg: Punct, cursor: Cursor) -> Option<(Lit, Cursor)> {
725 let (lit, rest) = cursor.literal()?;
726
727 let mut span = neg.span();
728 span = span.join(lit.span()).unwrap_or(span);
729
730 let mut repr = lit.to_string();
731 repr.insert(0, '-');
732
733 if !(repr.ends_with("f32") || repr.ends_with("f64")) {
734 if let Some((digits, suffix)) = value::parse_lit_int(&repr) {
735 if let Some(mut token) = value::to_literal(&repr, &digits, &suffix) {
736 token.set_span(span);
737 return Some((
738 Lit::Int(LitInt {
739 repr: Box::new(LitIntRepr {
740 token,
741 digits,
742 suffix,
743 }),
744 }),
745 rest,
746 ));
747 }
748 }
749 }
750
751 let (digits, suffix) = value::parse_lit_float(&repr)?;
752 let mut token = value::to_literal(&repr, &digits, &suffix)?;
753 token.set_span(span);
754 Some((
755 Lit::Float(LitFloat {
756 repr: Box::new(LitFloatRepr {
757 token,
758 digits,
759 suffix,
760 }),
761 }),
762 rest,
763 ))
764 }
765
e74abb32
XL
766 impl Parse for LitStr {
767 fn parse(input: ParseStream) -> Result<Self> {
768 let head = input.fork();
769 match input.parse()? {
770 Lit::Str(lit) => Ok(lit),
771 _ => Err(head.error("expected string literal")),
772 }
773 }
774 }
775
776 impl Parse for LitByteStr {
777 fn parse(input: ParseStream) -> Result<Self> {
778 let head = input.fork();
779 match input.parse()? {
780 Lit::ByteStr(lit) => Ok(lit),
781 _ => Err(head.error("expected byte string literal")),
782 }
783 }
784 }
785
786 impl Parse for LitByte {
787 fn parse(input: ParseStream) -> Result<Self> {
788 let head = input.fork();
789 match input.parse()? {
790 Lit::Byte(lit) => Ok(lit),
791 _ => Err(head.error("expected byte literal")),
792 }
793 }
794 }
795
796 impl Parse for LitChar {
797 fn parse(input: ParseStream) -> Result<Self> {
798 let head = input.fork();
799 match input.parse()? {
800 Lit::Char(lit) => Ok(lit),
801 _ => Err(head.error("expected character literal")),
802 }
803 }
804 }
805
806 impl Parse for LitInt {
807 fn parse(input: ParseStream) -> Result<Self> {
808 let head = input.fork();
809 match input.parse()? {
810 Lit::Int(lit) => Ok(lit),
811 _ => Err(head.error("expected integer literal")),
812 }
813 }
814 }
815
816 impl Parse for LitFloat {
817 fn parse(input: ParseStream) -> Result<Self> {
818 let head = input.fork();
819 match input.parse()? {
820 Lit::Float(lit) => Ok(lit),
821 _ => Err(head.error("expected floating point literal")),
822 }
823 }
824 }
825
826 impl Parse for LitBool {
827 fn parse(input: ParseStream) -> Result<Self> {
828 let head = input.fork();
829 match input.parse()? {
830 Lit::Bool(lit) => Ok(lit),
831 _ => Err(head.error("expected boolean literal")),
832 }
833 }
834 }
835}
836
837#[cfg(feature = "printing")]
838mod printing {
839 use super::*;
840 use proc_macro2::TokenStream;
841 use quote::{ToTokens, TokenStreamExt};
842
843 impl ToTokens for LitStr {
844 fn to_tokens(&self, tokens: &mut TokenStream) {
845 self.repr.token.to_tokens(tokens);
846 }
847 }
848
849 impl ToTokens for LitByteStr {
850 fn to_tokens(&self, tokens: &mut TokenStream) {
f035d41b 851 self.repr.token.to_tokens(tokens);
e74abb32
XL
852 }
853 }
854
855 impl ToTokens for LitByte {
856 fn to_tokens(&self, tokens: &mut TokenStream) {
f035d41b 857 self.repr.token.to_tokens(tokens);
e74abb32
XL
858 }
859 }
860
861 impl ToTokens for LitChar {
862 fn to_tokens(&self, tokens: &mut TokenStream) {
f035d41b 863 self.repr.token.to_tokens(tokens);
e74abb32
XL
864 }
865 }
866
867 impl ToTokens for LitInt {
868 fn to_tokens(&self, tokens: &mut TokenStream) {
869 self.repr.token.to_tokens(tokens);
870 }
871 }
872
873 impl ToTokens for LitFloat {
874 fn to_tokens(&self, tokens: &mut TokenStream) {
875 self.repr.token.to_tokens(tokens);
876 }
877 }
878
879 impl ToTokens for LitBool {
880 fn to_tokens(&self, tokens: &mut TokenStream) {
881 let s = if self.value { "true" } else { "false" };
882 tokens.append(Ident::new(s, self.span));
883 }
884 }
885}
886
887mod value {
888 use super::*;
889 use crate::bigint::BigInt;
890 use proc_macro2::TokenStream;
891 use std::char;
892 use std::ops::{Index, RangeFrom};
893
894 impl Lit {
895 /// Interpret a Syn literal from a proc-macro2 literal.
896 pub fn new(token: Literal) -> Self {
897 let repr = token.to_string();
898
899 match byte(&repr, 0) {
900 b'"' | b'r' => {
901 let (_, suffix) = parse_lit_str(&repr);
902 return Lit::Str(LitStr {
f035d41b 903 repr: Box::new(LitRepr { token, suffix }),
e74abb32
XL
904 });
905 }
906 b'b' => match byte(&repr, 1) {
907 b'"' | b'r' => {
f035d41b
XL
908 let (_, suffix) = parse_lit_byte_str(&repr);
909 return Lit::ByteStr(LitByteStr {
910 repr: Box::new(LitRepr { token, suffix }),
911 });
e74abb32
XL
912 }
913 b'\'' => {
f035d41b
XL
914 let (_, suffix) = parse_lit_byte(&repr);
915 return Lit::Byte(LitByte {
916 repr: Box::new(LitRepr { token, suffix }),
917 });
e74abb32
XL
918 }
919 _ => {}
920 },
921 b'\'' => {
f035d41b
XL
922 let (_, suffix) = parse_lit_char(&repr);
923 return Lit::Char(LitChar {
924 repr: Box::new(LitRepr { token, suffix }),
925 });
e74abb32
XL
926 }
927 b'0'..=b'9' | b'-' => {
928 if !(repr.ends_with("f32") || repr.ends_with("f64")) {
929 if let Some((digits, suffix)) = parse_lit_int(&repr) {
930 return Lit::Int(LitInt {
931 repr: Box::new(LitIntRepr {
932 token,
933 digits,
934 suffix,
935 }),
936 });
937 }
938 }
939 if let Some((digits, suffix)) = parse_lit_float(&repr) {
940 return Lit::Float(LitFloat {
941 repr: Box::new(LitFloatRepr {
942 token,
943 digits,
944 suffix,
945 }),
946 });
947 }
948 }
949 b't' | b'f' => {
950 if repr == "true" || repr == "false" {
951 return Lit::Bool(LitBool {
952 value: repr == "true",
953 span: token.span(),
954 });
955 }
956 }
957 _ => {}
958 }
959
960 panic!("Unrecognized literal: `{}`", repr);
961 }
f035d41b
XL
962
963 pub fn suffix(&self) -> &str {
964 match self {
965 Lit::Str(lit) => lit.suffix(),
966 Lit::ByteStr(lit) => lit.suffix(),
967 Lit::Byte(lit) => lit.suffix(),
968 Lit::Char(lit) => lit.suffix(),
969 Lit::Int(lit) => lit.suffix(),
970 Lit::Float(lit) => lit.suffix(),
971 Lit::Bool(_) | Lit::Verbatim(_) => "",
972 }
973 }
3dfed10e
XL
974
975 pub fn span(&self) -> Span {
976 match self {
977 Lit::Str(lit) => lit.span(),
978 Lit::ByteStr(lit) => lit.span(),
979 Lit::Byte(lit) => lit.span(),
980 Lit::Char(lit) => lit.span(),
981 Lit::Int(lit) => lit.span(),
982 Lit::Float(lit) => lit.span(),
983 Lit::Bool(lit) => lit.span,
984 Lit::Verbatim(lit) => lit.span(),
985 }
986 }
987
988 pub fn set_span(&mut self, span: Span) {
989 match self {
990 Lit::Str(lit) => lit.set_span(span),
991 Lit::ByteStr(lit) => lit.set_span(span),
992 Lit::Byte(lit) => lit.set_span(span),
993 Lit::Char(lit) => lit.set_span(span),
994 Lit::Int(lit) => lit.set_span(span),
995 Lit::Float(lit) => lit.set_span(span),
996 Lit::Bool(lit) => lit.span = span,
997 Lit::Verbatim(lit) => lit.set_span(span),
998 }
999 }
e74abb32
XL
1000 }
1001
1002 /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
1003 /// past the end of the input buffer.
1004 pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
1005 let s = s.as_ref();
1006 if idx < s.len() {
1007 s[idx]
1008 } else {
1009 0
1010 }
1011 }
1012
1013 fn next_chr(s: &str) -> char {
1014 s.chars().next().unwrap_or('\0')
1015 }
1016
1017 // Returns (content, suffix).
1018 pub fn parse_lit_str(s: &str) -> (Box<str>, Box<str>) {
1019 match byte(s, 0) {
1020 b'"' => parse_lit_str_cooked(s),
1021 b'r' => parse_lit_str_raw(s),
1022 _ => unreachable!(),
1023 }
1024 }
1025
1026 // Clippy false positive
1027 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
1028 #[allow(clippy::needless_continue)]
1029 fn parse_lit_str_cooked(mut s: &str) -> (Box<str>, Box<str>) {
1030 assert_eq!(byte(s, 0), b'"');
1031 s = &s[1..];
1032
1033 let mut content = String::new();
1034 'outer: loop {
1035 let ch = match byte(s, 0) {
1036 b'"' => break,
1037 b'\\' => {
1038 let b = byte(s, 1);
1039 s = &s[2..];
1040 match b {
1041 b'x' => {
1042 let (byte, rest) = backslash_x(s);
1043 s = rest;
1044 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
1045 char::from_u32(u32::from(byte)).unwrap()
1046 }
1047 b'u' => {
1048 let (chr, rest) = backslash_u(s);
1049 s = rest;
1050 chr
1051 }
1052 b'n' => '\n',
1053 b'r' => '\r',
1054 b't' => '\t',
1055 b'\\' => '\\',
1056 b'0' => '\0',
1057 b'\'' => '\'',
1058 b'"' => '"',
1059 b'\r' | b'\n' => loop {
1060 let ch = next_chr(s);
1061 if ch.is_whitespace() {
1062 s = &s[ch.len_utf8()..];
1063 } else {
1064 continue 'outer;
1065 }
1066 },
1067 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
1068 }
1069 }
1070 b'\r' => {
1071 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
1072 s = &s[2..];
1073 '\n'
1074 }
1075 _ => {
1076 let ch = next_chr(s);
1077 s = &s[ch.len_utf8()..];
1078 ch
1079 }
1080 };
1081 content.push(ch);
1082 }
1083
1084 assert!(s.starts_with('"'));
1085 let content = content.into_boxed_str();
1086 let suffix = s[1..].to_owned().into_boxed_str();
1087 (content, suffix)
1088 }
1089
1090 fn parse_lit_str_raw(mut s: &str) -> (Box<str>, Box<str>) {
1091 assert_eq!(byte(s, 0), b'r');
1092 s = &s[1..];
1093
1094 let mut pounds = 0;
1095 while byte(s, pounds) == b'#' {
1096 pounds += 1;
1097 }
1098 assert_eq!(byte(s, pounds), b'"');
f035d41b
XL
1099 let close = s.rfind('"').unwrap();
1100 for end in s[close + 1..close + 1 + pounds].bytes() {
e74abb32
XL
1101 assert_eq!(end, b'#');
1102 }
1103
f035d41b
XL
1104 let content = s[pounds + 1..close].to_owned().into_boxed_str();
1105 let suffix = s[close + 1 + pounds..].to_owned().into_boxed_str();
e74abb32
XL
1106 (content, suffix)
1107 }
1108
f035d41b
XL
1109 // Returns (content, suffix).
1110 pub fn parse_lit_byte_str(s: &str) -> (Vec<u8>, Box<str>) {
e74abb32
XL
1111 assert_eq!(byte(s, 0), b'b');
1112 match byte(s, 1) {
1113 b'"' => parse_lit_byte_str_cooked(s),
1114 b'r' => parse_lit_byte_str_raw(s),
1115 _ => unreachable!(),
1116 }
1117 }
1118
1119 // Clippy false positive
1120 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
1121 #[allow(clippy::needless_continue)]
f035d41b 1122 fn parse_lit_byte_str_cooked(mut s: &str) -> (Vec<u8>, Box<str>) {
e74abb32
XL
1123 assert_eq!(byte(s, 0), b'b');
1124 assert_eq!(byte(s, 1), b'"');
1125 s = &s[2..];
1126
1127 // We're going to want to have slices which don't respect codepoint boundaries.
f035d41b 1128 let mut v = s.as_bytes();
e74abb32
XL
1129
1130 let mut out = Vec::new();
1131 'outer: loop {
f035d41b 1132 let byte = match byte(v, 0) {
e74abb32
XL
1133 b'"' => break,
1134 b'\\' => {
f035d41b
XL
1135 let b = byte(v, 1);
1136 v = &v[2..];
e74abb32
XL
1137 match b {
1138 b'x' => {
f035d41b
XL
1139 let (b, rest) = backslash_x(v);
1140 v = rest;
e74abb32
XL
1141 b
1142 }
1143 b'n' => b'\n',
1144 b'r' => b'\r',
1145 b't' => b'\t',
1146 b'\\' => b'\\',
1147 b'0' => b'\0',
1148 b'\'' => b'\'',
1149 b'"' => b'"',
1150 b'\r' | b'\n' => loop {
f035d41b 1151 let byte = byte(v, 0);
e74abb32
XL
1152 let ch = char::from_u32(u32::from(byte)).unwrap();
1153 if ch.is_whitespace() {
f035d41b 1154 v = &v[1..];
e74abb32
XL
1155 } else {
1156 continue 'outer;
1157 }
1158 },
1159 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
1160 }
1161 }
1162 b'\r' => {
f035d41b
XL
1163 assert_eq!(byte(v, 1), b'\n', "Bare CR not allowed in string");
1164 v = &v[2..];
e74abb32
XL
1165 b'\n'
1166 }
1167 b => {
f035d41b 1168 v = &v[1..];
e74abb32
XL
1169 b
1170 }
1171 };
1172 out.push(byte);
1173 }
1174
f035d41b
XL
1175 assert_eq!(byte(v, 0), b'"');
1176 let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
1177 (out, suffix)
e74abb32
XL
1178 }
1179
f035d41b 1180 fn parse_lit_byte_str_raw(s: &str) -> (Vec<u8>, Box<str>) {
e74abb32 1181 assert_eq!(byte(s, 0), b'b');
f035d41b
XL
1182 let (value, suffix) = parse_lit_str_raw(&s[1..]);
1183 (String::from(value).into_bytes(), suffix)
e74abb32
XL
1184 }
1185
f035d41b
XL
1186 // Returns (value, suffix).
1187 pub fn parse_lit_byte(s: &str) -> (u8, Box<str>) {
e74abb32
XL
1188 assert_eq!(byte(s, 0), b'b');
1189 assert_eq!(byte(s, 1), b'\'');
1190
1191 // We're going to want to have slices which don't respect codepoint boundaries.
f035d41b 1192 let mut v = s[2..].as_bytes();
e74abb32 1193
f035d41b 1194 let b = match byte(v, 0) {
e74abb32 1195 b'\\' => {
f035d41b
XL
1196 let b = byte(v, 1);
1197 v = &v[2..];
e74abb32
XL
1198 match b {
1199 b'x' => {
f035d41b
XL
1200 let (b, rest) = backslash_x(v);
1201 v = rest;
e74abb32
XL
1202 b
1203 }
1204 b'n' => b'\n',
1205 b'r' => b'\r',
1206 b't' => b'\t',
1207 b'\\' => b'\\',
1208 b'0' => b'\0',
1209 b'\'' => b'\'',
1210 b'"' => b'"',
1211 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
1212 }
1213 }
1214 b => {
f035d41b 1215 v = &v[1..];
e74abb32
XL
1216 b
1217 }
1218 };
1219
f035d41b
XL
1220 assert_eq!(byte(v, 0), b'\'');
1221 let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
1222 (b, suffix)
e74abb32
XL
1223 }
1224
f035d41b
XL
1225 // Returns (value, suffix).
1226 pub fn parse_lit_char(mut s: &str) -> (char, Box<str>) {
e74abb32
XL
1227 assert_eq!(byte(s, 0), b'\'');
1228 s = &s[1..];
1229
1230 let ch = match byte(s, 0) {
1231 b'\\' => {
1232 let b = byte(s, 1);
1233 s = &s[2..];
1234 match b {
1235 b'x' => {
1236 let (byte, rest) = backslash_x(s);
1237 s = rest;
1238 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
1239 char::from_u32(u32::from(byte)).unwrap()
1240 }
1241 b'u' => {
1242 let (chr, rest) = backslash_u(s);
1243 s = rest;
1244 chr
1245 }
1246 b'n' => '\n',
1247 b'r' => '\r',
1248 b't' => '\t',
1249 b'\\' => '\\',
1250 b'0' => '\0',
1251 b'\'' => '\'',
1252 b'"' => '"',
1253 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
1254 }
1255 }
1256 _ => {
1257 let ch = next_chr(s);
1258 s = &s[ch.len_utf8()..];
1259 ch
1260 }
1261 };
f035d41b
XL
1262 assert_eq!(byte(s, 0), b'\'');
1263 let suffix = s[1..].to_owned().into_boxed_str();
1264 (ch, suffix)
e74abb32
XL
1265 }
1266
1267 fn backslash_x<S>(s: &S) -> (u8, &S)
1268 where
1269 S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
1270 {
1271 let mut ch = 0;
1272 let b0 = byte(s, 0);
1273 let b1 = byte(s, 1);
1274 ch += 0x10
1275 * match b0 {
1276 b'0'..=b'9' => b0 - b'0',
1277 b'a'..=b'f' => 10 + (b0 - b'a'),
1278 b'A'..=b'F' => 10 + (b0 - b'A'),
1279 _ => panic!("unexpected non-hex character after \\x"),
1280 };
1281 ch += match b1 {
1282 b'0'..=b'9' => b1 - b'0',
1283 b'a'..=b'f' => 10 + (b1 - b'a'),
1284 b'A'..=b'F' => 10 + (b1 - b'A'),
1285 _ => panic!("unexpected non-hex character after \\x"),
1286 };
1287 (ch, &s[2..])
1288 }
1289
1290 fn backslash_u(mut s: &str) -> (char, &str) {
1291 if byte(s, 0) != b'{' {
1292 panic!("expected {{ after \\u");
1293 }
1294 s = &s[1..];
1295
1296 let mut ch = 0;
1297 for _ in 0..6 {
1298 let b = byte(s, 0);
1299 match b {
1300 b'0'..=b'9' => {
1301 ch *= 0x10;
1302 ch += u32::from(b - b'0');
1303 s = &s[1..];
1304 }
1305 b'a'..=b'f' => {
1306 ch *= 0x10;
1307 ch += u32::from(10 + b - b'a');
1308 s = &s[1..];
1309 }
1310 b'A'..=b'F' => {
1311 ch *= 0x10;
1312 ch += u32::from(10 + b - b'A');
1313 s = &s[1..];
1314 }
1315 b'}' => break,
1316 _ => panic!("unexpected non-hex character after \\u"),
1317 }
1318 }
1319 assert!(byte(s, 0) == b'}');
1320 s = &s[1..];
1321
1322 if let Some(ch) = char::from_u32(ch) {
1323 (ch, s)
1324 } else {
1325 panic!("character code {:x} is not a valid unicode character", ch);
1326 }
1327 }
1328
1329 // Returns base 10 digits and suffix.
1330 pub fn parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)> {
1331 let negative = byte(s, 0) == b'-';
1332 if negative {
1333 s = &s[1..];
1334 }
1335
1336 let base = match (byte(s, 0), byte(s, 1)) {
1337 (b'0', b'x') => {
1338 s = &s[2..];
1339 16
1340 }
1341 (b'0', b'o') => {
1342 s = &s[2..];
1343 8
1344 }
1345 (b'0', b'b') => {
1346 s = &s[2..];
1347 2
1348 }
1349 (b'0'..=b'9', _) => 10,
1350 _ => return None,
1351 };
1352
1353 let mut value = BigInt::new();
1354 loop {
1355 let b = byte(s, 0);
1356 let digit = match b {
1357 b'0'..=b'9' => b - b'0',
1358 b'a'..=b'f' if base > 10 => b - b'a' + 10,
1359 b'A'..=b'F' if base > 10 => b - b'A' + 10,
1360 b'_' => {
1361 s = &s[1..];
1362 continue;
1363 }
1364 // NOTE: Looking at a floating point literal, we don't want to
1365 // consider these integers.
1366 b'.' if base == 10 => return None,
1367 b'e' | b'E' if base == 10 => return None,
1368 _ => break,
1369 };
1370
1371 if digit >= base {
1372 return None;
1373 }
1374
1375 value *= base;
1376 value += digit;
1377 s = &s[1..];
1378 }
1379
1380 let suffix = s;
1381 if suffix.is_empty() || crate::ident::xid_ok(&suffix) {
1382 let mut repr = value.to_string();
1383 if negative {
1384 repr.insert(0, '-');
1385 }
1386 Some((repr.into_boxed_str(), suffix.to_owned().into_boxed_str()))
1387 } else {
1388 None
1389 }
1390 }
1391
1392 // Returns base 10 digits and suffix.
1393 pub fn parse_lit_float(input: &str) -> Option<(Box<str>, Box<str>)> {
1394 // Rust's floating point literals are very similar to the ones parsed by
1395 // the standard library, except that rust's literals can contain
1396 // ignorable underscores. Let's remove those underscores.
1397
1398 let mut bytes = input.to_owned().into_bytes();
1399
1400 let start = (*bytes.get(0)? == b'-') as usize;
1401 match bytes.get(start)? {
1402 b'0'..=b'9' => {}
1403 _ => return None,
1404 }
1405
1406 let mut read = start;
1407 let mut write = start;
1408 let mut has_dot = false;
1409 let mut has_e = false;
1410 let mut has_sign = false;
1411 let mut has_exponent = false;
1412 while read < bytes.len() {
1413 match bytes[read] {
1414 b'_' => {
1415 // Don't increase write
1416 read += 1;
1417 continue;
1418 }
1419 b'0'..=b'9' => {
1420 if has_e {
1421 has_exponent = true;
1422 }
1423 bytes[write] = bytes[read];
1424 }
1425 b'.' => {
1426 if has_e || has_dot {
1427 return None;
1428 }
1429 has_dot = true;
1430 bytes[write] = b'.';
1431 }
1432 b'e' | b'E' => {
1433 if has_e {
1b1a35ee
XL
1434 if has_exponent {
1435 break;
1436 } else {
1437 return None;
1438 }
e74abb32
XL
1439 }
1440 has_e = true;
1441 bytes[write] = b'e';
1442 }
1443 b'-' | b'+' => {
1444 if has_sign || has_exponent || !has_e {
1445 return None;
1446 }
1447 has_sign = true;
1448 if bytes[read] == b'-' {
1449 bytes[write] = bytes[read];
1450 } else {
1451 // Omit '+'
1452 read += 1;
1453 continue;
1454 }
1455 }
1456 _ => break,
1457 }
1458 read += 1;
1459 write += 1;
1460 }
1461
1462 if has_e && !has_exponent {
1463 return None;
1464 }
1465
1466 let mut digits = String::from_utf8(bytes).unwrap();
1467 let suffix = digits.split_off(read);
1468 digits.truncate(write);
1469 if suffix.is_empty() || crate::ident::xid_ok(&suffix) {
1470 Some((digits.into_boxed_str(), suffix.into_boxed_str()))
1471 } else {
1472 None
1473 }
1474 }
1475
f035d41b
XL
1476 pub fn to_literal(repr: &str, digits: &str, suffix: &str) -> Option<Literal> {
1477 if repr.starts_with('-') {
1478 if suffix == "f64" {
1479 digits.parse().ok().map(Literal::f64_suffixed)
1480 } else if suffix == "f32" {
1481 digits.parse().ok().map(Literal::f32_suffixed)
1482 } else if suffix == "i64" {
1483 digits.parse().ok().map(Literal::i64_suffixed)
1484 } else if suffix == "i32" {
1485 digits.parse().ok().map(Literal::i32_suffixed)
1486 } else if suffix == "i16" {
1487 digits.parse().ok().map(Literal::i16_suffixed)
1488 } else if suffix == "i8" {
1489 digits.parse().ok().map(Literal::i8_suffixed)
1490 } else if !suffix.is_empty() {
1491 None
1492 } else if digits.contains('.') {
1493 digits.parse().ok().map(Literal::f64_unsuffixed)
1494 } else {
1495 digits.parse().ok().map(Literal::i64_unsuffixed)
1496 }
1497 } else {
1498 let stream = repr.parse::<TokenStream>().unwrap();
1499 match stream.into_iter().next().unwrap() {
1500 TokenTree::Literal(l) => Some(l),
1501 _ => unreachable!(),
1502 }
e74abb32
XL
1503 }
1504 }
1505}