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