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