| 1 | |
| 2 |
|
| 3 | #[cfg(feature = "parsing")]
|
| 4 | use crate::lookahead;
|
| 5 | #[cfg(feature = "parsing")]
|
| 6 | use crate::parse::{Parse, Parser};
|
| 7 | use crate::{Error, Result};
|
| 8 | use proc_macro2::{Ident, Literal, Span};
|
| 9 | #[cfg(feature = "parsing")]
|
| 10 | use proc_macro2::{TokenStream, TokenTree};
|
| 11 | use std::ffi::{CStr, CString};
|
| 12 | use std::fmt::{self, Display};
|
| 13 | #[cfg(feature = "extra-traits")]
|
| 14 | use std::hash::{Hash, Hasher};
|
| 15 | use std::str::{self, FromStr};
|
| 16 |
|
| 17 | ast_enum_of_structs! {
|
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 | |
| 25 | #[non_exhaustive]
|
| 26 | pub enum Lit {
|
| 27 | |
| 28 | Str(LitStr),
|
| 29 |
|
| 30 | |
| 31 | ByteStr(LitByteStr),
|
| 32 |
|
| 33 | |
| 34 | CStr(LitCStr),
|
| 35 |
|
| 36 | |
| 37 | Byte(LitByte),
|
| 38 |
|
| 39 | |
| 40 | Char(LitChar),
|
| 41 |
|
| 42 | |
| 43 | Int(LitInt),
|
| 44 |
|
| 45 | |
| 46 | |
| 47 | |
| 48 | Float(LitFloat),
|
| 49 |
|
| 50 | |
| 51 | Bool(LitBool),
|
| 52 |
|
| 53 | |
| 54 | Verbatim(Literal),
|
| 55 | }
|
| 56 | }
|
| 57 |
|
| 58 | ast_struct! {
|
| 59 | |
| 60 | pub struct LitStr {
|
| 61 | repr: Box<LitRepr>,
|
| 62 | }
|
| 63 | }
|
| 64 |
|
| 65 | ast_struct! {
|
| 66 | |
| 67 | pub struct LitByteStr {
|
| 68 | repr: Box<LitRepr>,
|
| 69 | }
|
| 70 | }
|
| 71 |
|
| 72 | ast_struct! {
|
| 73 | |
| 74 | pub struct LitCStr {
|
| 75 | repr: Box<LitRepr>,
|
| 76 | }
|
| 77 | }
|
| 78 |
|
| 79 | ast_struct! {
|
| 80 | |
| 81 | pub struct LitByte {
|
| 82 | repr: Box<LitRepr>,
|
| 83 | }
|
| 84 | }
|
| 85 |
|
| 86 | ast_struct! {
|
| 87 | |
| 88 | pub struct LitChar {
|
| 89 | repr: Box<LitRepr>,
|
| 90 | }
|
| 91 | }
|
| 92 |
|
| 93 | struct LitRepr {
|
| 94 | token: Literal,
|
| 95 | suffix: Box<str>,
|
| 96 | }
|
| 97 |
|
| 98 | ast_struct! {
|
| 99 | |
| 100 | pub struct LitInt {
|
| 101 | repr: Box<LitIntRepr>,
|
| 102 | }
|
| 103 | }
|
| 104 |
|
| 105 | struct LitIntRepr {
|
| 106 | token: Literal,
|
| 107 | digits: Box<str>,
|
| 108 | suffix: Box<str>,
|
| 109 | }
|
| 110 |
|
| 111 | ast_struct! {
|
| 112 | |
| 113 | |
| 114 | |
| 115 | pub struct LitFloat {
|
| 116 | repr: Box<LitFloatRepr>,
|
| 117 | }
|
| 118 | }
|
| 119 |
|
| 120 | struct LitFloatRepr {
|
| 121 | token: Literal,
|
| 122 | digits: Box<str>,
|
| 123 | suffix: Box<str>,
|
| 124 | }
|
| 125 |
|
| 126 | ast_struct! {
|
| 127 | |
| 128 | pub struct LitBool {
|
| 129 | pub value: bool,
|
| 130 | pub span: Span,
|
| 131 | }
|
| 132 | }
|
| 133 |
|
| 134 | impl LitStr {
|
| 135 | pub fn new(value: &str, span: Span) -> Self {
|
| 136 | let mut token = Literal::string(value);
|
| 137 | token.set_span(span);
|
| 138 | LitStr {
|
| 139 | repr: Box::new(LitRepr {
|
| 140 | token,
|
| 141 | suffix: Box::<str>::default(),
|
| 142 | }),
|
| 143 | }
|
| 144 | }
|
| 145 |
|
| 146 | pub fn value(&self) -> String {
|
| 147 | let repr = self.repr.token.to_string();
|
| 148 | let (value, _suffix) = value::parse_lit_str(&repr);
|
| 149 | String::from(value)
|
| 150 | }
|
| 151 |
|
| 152 | |
| 153 | |
| 154 | |
| 155 | |
| 156 | |
| 157 | |
| 158 | |
| 159 | |
| 160 | |
| 161 | |
| 162 | |
| 163 | |
| 164 | |
| 165 | |
| 166 | |
| 167 | |
| 168 | |
| 169 | |
| 170 | |
| 171 | |
| 172 | |
| 173 | |
| 174 | |
| 175 | |
| 176 | |
| 177 | |
| 178 | |
| 179 | |
| 180 | |
| 181 | |
| 182 | |
| 183 | #[cfg(feature = "parsing")]
|
| 184 | #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
| 185 | pub fn parse<T: Parse>(&self) -> Result<T> {
|
| 186 | self.parse_with(T::parse)
|
| 187 | }
|
| 188 |
|
| 189 | |
| 190 | |
| 191 | |
| 192 | |
| 193 | |
| 194 | |
| 195 | |
| 196 | |
| 197 | |
| 198 | |
| 199 | |
| 200 | |
| 201 | |
| 202 | |
| 203 | |
| 204 | |
| 205 | |
| 206 | |
| 207 | |
| 208 | |
| 209 | |
| 210 | |
| 211 | |
| 212 | |
| 213 | #[cfg(feature = "parsing")]
|
| 214 | #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
| 215 | pub fn parse_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
|
| 216 | use proc_macro2::Group;
|
| 217 |
|
| 218 | |
| 219 | fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
|
| 220 | stream
|
| 221 | .into_iter()
|
| 222 | .map(|token| respan_token_tree(token, span))
|
| 223 | .collect()
|
| 224 | }
|
| 225 |
|
| 226 | |
| 227 | fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
|
| 228 | match &mut token {
|
| 229 | TokenTree::Group(g) => {
|
| 230 | let stream = respan_token_stream(g.stream(), span);
|
| 231 | *g = Group::new(g.delimiter(), stream);
|
| 232 | g.set_span(span);
|
| 233 | }
|
| 234 | other => other.set_span(span),
|
| 235 | }
|
| 236 | token
|
| 237 | }
|
| 238 |
|
| 239 | |
| 240 | |
| 241 | let span = self.span();
|
| 242 | let mut tokens = TokenStream::from_str(&self.value())?;
|
| 243 | tokens = respan_token_stream(tokens, span);
|
| 244 |
|
| 245 | let result = crate::parse::parse_scoped(parser, span, tokens)?;
|
| 246 |
|
| 247 | let suffix = self.suffix();
|
| 248 | if !suffix.is_empty() {
|
| 249 | return Err(Error::new(
|
| 250 | self.span(),
|
| 251 | format!("unexpected suffix `{}` on string literal", suffix),
|
| 252 | ));
|
| 253 | }
|
| 254 |
|
| 255 | Ok(result)
|
| 256 | }
|
| 257 |
|
| 258 | pub fn span(&self) -> Span {
|
| 259 | self.repr.token.span()
|
| 260 | }
|
| 261 |
|
| 262 | pub fn set_span(&mut self, span: Span) {
|
| 263 | self.repr.token.set_span(span);
|
| 264 | }
|
| 265 |
|
| 266 | pub fn suffix(&self) -> &str {
|
| 267 | &self.repr.suffix
|
| 268 | }
|
| 269 |
|
| 270 | pub fn token(&self) -> Literal {
|
| 271 | self.repr.token.clone()
|
| 272 | }
|
| 273 | }
|
| 274 |
|
| 275 | impl LitByteStr {
|
| 276 | pub fn new(value: &[u8], span: Span) -> Self {
|
| 277 | let mut token = Literal::byte_string(value);
|
| 278 | token.set_span(span);
|
| 279 | LitByteStr {
|
| 280 | repr: Box::new(LitRepr {
|
| 281 | token,
|
| 282 | suffix: Box::<str>::default(),
|
| 283 | }),
|
| 284 | }
|
| 285 | }
|
| 286 |
|
| 287 | pub fn value(&self) -> Vec<u8> {
|
| 288 | let repr = self.repr.token.to_string();
|
| 289 | let (value, _suffix) = value::parse_lit_byte_str(&repr);
|
| 290 | value
|
| 291 | }
|
| 292 |
|
| 293 | pub fn span(&self) -> Span {
|
| 294 | self.repr.token.span()
|
| 295 | }
|
| 296 |
|
| 297 | pub fn set_span(&mut self, span: Span) {
|
| 298 | self.repr.token.set_span(span);
|
| 299 | }
|
| 300 |
|
| 301 | pub fn suffix(&self) -> &str {
|
| 302 | &self.repr.suffix
|
| 303 | }
|
| 304 |
|
| 305 | pub fn token(&self) -> Literal {
|
| 306 | self.repr.token.clone()
|
| 307 | }
|
| 308 | }
|
| 309 |
|
| 310 | impl LitCStr {
|
| 311 | pub fn new(value: &CStr, span: Span) -> Self {
|
| 312 | let mut token = Literal::c_string(value);
|
| 313 | token.set_span(span);
|
| 314 | LitCStr {
|
| 315 | repr: Box::new(LitRepr {
|
| 316 | token,
|
| 317 | suffix: Box::<str>::default(),
|
| 318 | }),
|
| 319 | }
|
| 320 | }
|
| 321 |
|
| 322 | pub fn value(&self) -> CString {
|
| 323 | let repr = self.repr.token.to_string();
|
| 324 | let (value, _suffix) = value::parse_lit_c_str(&repr);
|
| 325 | value
|
| 326 | }
|
| 327 |
|
| 328 | pub fn span(&self) -> Span {
|
| 329 | self.repr.token.span()
|
| 330 | }
|
| 331 |
|
| 332 | pub fn set_span(&mut self, span: Span) {
|
| 333 | self.repr.token.set_span(span);
|
| 334 | }
|
| 335 |
|
| 336 | pub fn suffix(&self) -> &str {
|
| 337 | &self.repr.suffix
|
| 338 | }
|
| 339 |
|
| 340 | pub fn token(&self) -> Literal {
|
| 341 | self.repr.token.clone()
|
| 342 | }
|
| 343 | }
|
| 344 |
|
| 345 | impl LitByte {
|
| 346 | pub fn new(value: u8, span: Span) -> Self {
|
| 347 | let mut token = Literal::u8_suffixed(value);
|
| 348 | token.set_span(span);
|
| 349 | LitByte {
|
| 350 | repr: Box::new(LitRepr {
|
| 351 | token,
|
| 352 | suffix: Box::<str>::default(),
|
| 353 | }),
|
| 354 | }
|
| 355 | }
|
| 356 |
|
| 357 | pub fn value(&self) -> u8 {
|
| 358 | let repr = self.repr.token.to_string();
|
| 359 | let (value, _suffix) = value::parse_lit_byte(&repr);
|
| 360 | value
|
| 361 | }
|
| 362 |
|
| 363 | pub fn span(&self) -> Span {
|
| 364 | self.repr.token.span()
|
| 365 | }
|
| 366 |
|
| 367 | pub fn set_span(&mut self, span: Span) {
|
| 368 | self.repr.token.set_span(span);
|
| 369 | }
|
| 370 |
|
| 371 | pub fn suffix(&self) -> &str {
|
| 372 | &self.repr.suffix
|
| 373 | }
|
| 374 |
|
| 375 | pub fn token(&self) -> Literal {
|
| 376 | self.repr.token.clone()
|
| 377 | }
|
| 378 | }
|
| 379 |
|
| 380 | impl LitChar {
|
| 381 | pub fn new(value: char, span: Span) -> Self {
|
| 382 | let mut token = Literal::character(value);
|
| 383 | token.set_span(span);
|
| 384 | LitChar {
|
| 385 | repr: Box::new(LitRepr {
|
| 386 | token,
|
| 387 | suffix: Box::<str>::default(),
|
| 388 | }),
|
| 389 | }
|
| 390 | }
|
| 391 |
|
| 392 | pub fn value(&self) -> char {
|
| 393 | let repr = self.repr.token.to_string();
|
| 394 | let (value, _suffix) = value::parse_lit_char(&repr);
|
| 395 | value
|
| 396 | }
|
| 397 |
|
| 398 | pub fn span(&self) -> Span {
|
| 399 | self.repr.token.span()
|
| 400 | }
|
| 401 |
|
| 402 | pub fn set_span(&mut self, span: Span) {
|
| 403 | self.repr.token.set_span(span);
|
| 404 | }
|
| 405 |
|
| 406 | pub fn suffix(&self) -> &str {
|
| 407 | &self.repr.suffix
|
| 408 | }
|
| 409 |
|
| 410 | pub fn token(&self) -> Literal {
|
| 411 | self.repr.token.clone()
|
| 412 | }
|
| 413 | }
|
| 414 |
|
| 415 | impl LitInt {
|
| 416 | pub fn new(repr: &str, span: Span) -> Self {
|
| 417 | let (digits, suffix) = match value::parse_lit_int(repr) {
|
| 418 | Some(parse) => parse,
|
| 419 | None => panic!("not an integer literal: `{}`", repr),
|
| 420 | };
|
| 421 |
|
| 422 | let mut token: Literal = repr.parse().unwrap();
|
| 423 | token.set_span(span);
|
| 424 | LitInt {
|
| 425 | repr: Box::new(LitIntRepr {
|
| 426 | token,
|
| 427 | digits,
|
| 428 | suffix,
|
| 429 | }),
|
| 430 | }
|
| 431 | }
|
| 432 |
|
| 433 | pub fn base10_digits(&self) -> &str {
|
| 434 | &self.repr.digits
|
| 435 | }
|
| 436 |
|
| 437 | |
| 438 | |
| 439 | |
| 440 | |
| 441 | |
| 442 | |
| 443 | |
| 444 | |
| 445 | |
| 446 | |
| 447 | |
| 448 | |
| 449 | |
| 450 | |
| 451 | |
| 452 | |
| 453 | |
| 454 | |
| 455 | |
| 456 | |
| 457 | |
| 458 | |
| 459 | pub fn base10_parse<N>(&self) -> Result<N>
|
| 460 | where
|
| 461 | N: FromStr,
|
| 462 | N::Err: Display,
|
| 463 | {
|
| 464 | self.base10_digits()
|
| 465 | .parse()
|
| 466 | .map_err(|err| Error::new(self.span(), err))
|
| 467 | }
|
| 468 |
|
| 469 | pub fn suffix(&self) -> &str {
|
| 470 | &self.repr.suffix
|
| 471 | }
|
| 472 |
|
| 473 | pub fn span(&self) -> Span {
|
| 474 | self.repr.token.span()
|
| 475 | }
|
| 476 |
|
| 477 | pub fn set_span(&mut self, span: Span) {
|
| 478 | self.repr.token.set_span(span);
|
| 479 | }
|
| 480 |
|
| 481 | pub fn token(&self) -> Literal {
|
| 482 | self.repr.token.clone()
|
| 483 | }
|
| 484 | }
|
| 485 |
|
| 486 | impl From<Literal> for LitInt {
|
| 487 | fn from(token: Literal) -> Self {
|
| 488 | let repr = token.to_string();
|
| 489 | if let Some((digits, suffix)) = value::parse_lit_int(&repr) {
|
| 490 | LitInt {
|
| 491 | repr: Box::new(LitIntRepr {
|
| 492 | token,
|
| 493 | digits,
|
| 494 | suffix,
|
| 495 | }),
|
| 496 | }
|
| 497 | } else {
|
| 498 | panic!("not an integer literal: `{}`", repr);
|
| 499 | }
|
| 500 | }
|
| 501 | }
|
| 502 |
|
| 503 | impl Display for LitInt {
|
| 504 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
| 505 | self.repr.token.fmt(formatter)
|
| 506 | }
|
| 507 | }
|
| 508 |
|
| 509 | impl LitFloat {
|
| 510 | pub fn new(repr: &str, span: Span) -> Self {
|
| 511 | let (digits, suffix) = match value::parse_lit_float(repr) {
|
| 512 | Some(parse) => parse,
|
| 513 | None => panic!("not a float literal: `{}`", repr),
|
| 514 | };
|
| 515 |
|
| 516 | let mut token: Literal = repr.parse().unwrap();
|
| 517 | token.set_span(span);
|
| 518 | LitFloat {
|
| 519 | repr: Box::new(LitFloatRepr {
|
| 520 | token,
|
| 521 | digits,
|
| 522 | suffix,
|
| 523 | }),
|
| 524 | }
|
| 525 | }
|
| 526 |
|
| 527 | pub fn base10_digits(&self) -> &str {
|
| 528 | &self.repr.digits
|
| 529 | }
|
| 530 |
|
| 531 | pub fn base10_parse<N>(&self) -> Result<N>
|
| 532 | where
|
| 533 | N: FromStr,
|
| 534 | N::Err: Display,
|
| 535 | {
|
| 536 | self.base10_digits()
|
| 537 | .parse()
|
| 538 | .map_err(|err| Error::new(self.span(), err))
|
| 539 | }
|
| 540 |
|
| 541 | pub fn suffix(&self) -> &str {
|
| 542 | &self.repr.suffix
|
| 543 | }
|
| 544 |
|
| 545 | pub fn span(&self) -> Span {
|
| 546 | self.repr.token.span()
|
| 547 | }
|
| 548 |
|
| 549 | pub fn set_span(&mut self, span: Span) {
|
| 550 | self.repr.token.set_span(span);
|
| 551 | }
|
| 552 |
|
| 553 | pub fn token(&self) -> Literal {
|
| 554 | self.repr.token.clone()
|
| 555 | }
|
| 556 | }
|
| 557 |
|
| 558 | impl From<Literal> for LitFloat {
|
| 559 | fn from(token: Literal) -> Self {
|
| 560 | let repr = token.to_string();
|
| 561 | if let Some((digits, suffix)) = value::parse_lit_float(&repr) {
|
| 562 | LitFloat {
|
| 563 | repr: Box::new(LitFloatRepr {
|
| 564 | token,
|
| 565 | digits,
|
| 566 | suffix,
|
| 567 | }),
|
| 568 | }
|
| 569 | } else {
|
| 570 | panic!("not a float literal: `{}`", repr);
|
| 571 | }
|
| 572 | }
|
| 573 | }
|
| 574 |
|
| 575 | impl Display for LitFloat {
|
| 576 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
| 577 | self.repr.token.fmt(formatter)
|
| 578 | }
|
| 579 | }
|
| 580 |
|
| 581 | impl LitBool {
|
| 582 | pub fn new(value: bool, span: Span) -> Self {
|
| 583 | LitBool { value, span }
|
| 584 | }
|
| 585 |
|
| 586 | pub fn value(&self) -> bool {
|
| 587 | self.value
|
| 588 | }
|
| 589 |
|
| 590 | pub fn span(&self) -> Span {
|
| 591 | self.span
|
| 592 | }
|
| 593 |
|
| 594 | pub fn set_span(&mut self, span: Span) {
|
| 595 | self.span = span;
|
| 596 | }
|
| 597 |
|
| 598 | pub fn token(&self) -> Ident {
|
| 599 | let s = if self.value { "true" } else { "false" };
|
| 600 | Ident::new(s, self.span)
|
| 601 | }
|
| 602 | }
|
| 603 |
|
| 604 | #[cfg(feature = "extra-traits")]
|
| 605 | mod debug_impls {
|
| 606 | use crate::lit::{LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr};
|
| 607 | use std::fmt::{self, Debug};
|
| 608 |
|
| 609 | #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
| 610 | impl Debug for LitStr {
|
| 611 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
| 612 | self.debug(formatter, "LitStr")
|
| 613 | }
|
| 614 | }
|
| 615 |
|
| 616 | impl LitStr {
|
| 617 | 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(docsrs, doc(cfg(feature = "extra-traits")))]
|
| 626 | impl Debug for LitByteStr {
|
| 627 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
| 628 | self.debug(formatter, "LitByteStr")
|
| 629 | }
|
| 630 | }
|
| 631 |
|
| 632 | impl LitByteStr {
|
| 633 | 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(docsrs, doc(cfg(feature = "extra-traits")))]
|
| 642 | impl Debug for LitCStr {
|
| 643 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
| 644 | self.debug(formatter, "LitCStr")
|
| 645 | }
|
| 646 | }
|
| 647 |
|
| 648 | impl LitCStr {
|
| 649 | 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(docsrs, doc(cfg(feature = "extra-traits")))]
|
| 658 | impl Debug for LitByte {
|
| 659 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
| 660 | self.debug(formatter, "LitByte")
|
| 661 | }
|
| 662 | }
|
| 663 |
|
| 664 | impl LitByte {
|
| 665 | pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
|
| 666 | formatter
|
| 667 | .debug_struct(name)
|
| 668 | .field("token", &format_args!("{}", self.repr.token))
|
| 669 | .finish()
|
| 670 | }
|
| 671 | }
|
| 672 |
|
| 673 | #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
| 674 | impl Debug for LitChar {
|
| 675 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
| 676 | self.debug(formatter, "LitChar")
|
| 677 | }
|
| 678 | }
|
| 679 |
|
| 680 | impl LitChar {
|
| 681 | pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
|
| 682 | formatter
|
| 683 | .debug_struct(name)
|
| 684 | .field("token", &format_args!("{}", self.repr.token))
|
| 685 | .finish()
|
| 686 | }
|
| 687 | }
|
| 688 |
|
| 689 | #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
| 690 | impl Debug for LitInt {
|
| 691 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
| 692 | self.debug(formatter, "LitInt")
|
| 693 | }
|
| 694 | }
|
| 695 |
|
| 696 | impl LitInt {
|
| 697 | pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
|
| 698 | formatter
|
| 699 | .debug_struct(name)
|
| 700 | .field("token", &format_args!("{}", self.repr.token))
|
| 701 | .finish()
|
| 702 | }
|
| 703 | }
|
| 704 |
|
| 705 | #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
| 706 | impl Debug for LitFloat {
|
| 707 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
| 708 | self.debug(formatter, "LitFloat")
|
| 709 | }
|
| 710 | }
|
| 711 |
|
| 712 | impl LitFloat {
|
| 713 | pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
|
| 714 | formatter
|
| 715 | .debug_struct(name)
|
| 716 | .field("token", &format_args!("{}", self.repr.token))
|
| 717 | .finish()
|
| 718 | }
|
| 719 | }
|
| 720 |
|
| 721 | #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
| 722 | impl Debug for LitBool {
|
| 723 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
| 724 | self.debug(formatter, "LitBool")
|
| 725 | }
|
| 726 | }
|
| 727 |
|
| 728 | impl LitBool {
|
| 729 | pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
|
| 730 | formatter
|
| 731 | .debug_struct(name)
|
| 732 | .field("value", &self.value)
|
| 733 | .finish()
|
| 734 | }
|
| 735 | }
|
| 736 | }
|
| 737 |
|
| 738 | #[cfg(feature = "clone-impls")]
|
| 739 | #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
| 740 | impl Clone for LitRepr {
|
| 741 | fn clone(&self) -> Self {
|
| 742 | LitRepr {
|
| 743 | token: self.token.clone(),
|
| 744 | suffix: self.suffix.clone(),
|
| 745 | }
|
| 746 | }
|
| 747 | }
|
| 748 |
|
| 749 | #[cfg(feature = "clone-impls")]
|
| 750 | #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
| 751 | impl Clone for LitIntRepr {
|
| 752 | fn clone(&self) -> Self {
|
| 753 | LitIntRepr {
|
| 754 | token: self.token.clone(),
|
| 755 | digits: self.digits.clone(),
|
| 756 | suffix: self.suffix.clone(),
|
| 757 | }
|
| 758 | }
|
| 759 | }
|
| 760 |
|
| 761 | #[cfg(feature = "clone-impls")]
|
| 762 | #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
| 763 | impl Clone for LitFloatRepr {
|
| 764 | fn clone(&self) -> Self {
|
| 765 | LitFloatRepr {
|
| 766 | token: self.token.clone(),
|
| 767 | digits: self.digits.clone(),
|
| 768 | suffix: self.suffix.clone(),
|
| 769 | }
|
| 770 | }
|
| 771 | }
|
| 772 |
|
| 773 | macro_rules! lit_extra_traits {
|
| 774 | ($ty:ident) => {
|
| 775 | #[cfg(feature = "clone-impls")]
|
| 776 | #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
| 777 | impl Clone for $ty {
|
| 778 | fn clone(&self) -> Self {
|
| 779 | $ty {
|
| 780 | repr: self.repr.clone(),
|
| 781 | }
|
| 782 | }
|
| 783 | }
|
| 784 |
|
| 785 | #[cfg(feature = "extra-traits")]
|
| 786 | #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
| 787 | impl PartialEq for $ty {
|
| 788 | fn eq(&self, other: &Self) -> bool {
|
| 789 | self.repr.token.to_string() == other.repr.token.to_string()
|
| 790 | }
|
| 791 | }
|
| 792 |
|
| 793 | #[cfg(feature = "extra-traits")]
|
| 794 | #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
| 795 | impl Hash for $ty {
|
| 796 | fn hash<H>(&self, state: &mut H)
|
| 797 | where
|
| 798 | H: Hasher,
|
| 799 | {
|
| 800 | self.repr.token.to_string().hash(state);
|
| 801 | }
|
| 802 | }
|
| 803 |
|
| 804 | #[cfg(feature = "parsing")]
|
| 805 | pub_if_not_doc! {
|
| 806 | #[doc(hidden)]
|
| 807 | #[allow(non_snake_case)]
|
| 808 | pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
|
| 809 | match marker {}
|
| 810 | }
|
| 811 | }
|
| 812 | };
|
| 813 | }
|
| 814 |
|
| 815 | lit_extra_traits!(LitStr);
|
| 816 | lit_extra_traits!(LitByteStr);
|
| 817 | lit_extra_traits!(LitCStr);
|
| 818 | lit_extra_traits!(LitByte);
|
| 819 | lit_extra_traits!(LitChar);
|
| 820 | lit_extra_traits!(LitInt);
|
| 821 | lit_extra_traits!(LitFloat);
|
| 822 |
|
| 823 | #[cfg(feature = "parsing")]
|
| 824 | pub_if_not_doc! {
|
| 825 | #[doc(hidden)]
|
| 826 | #[allow(non_snake_case)]
|
| 827 | pub fn LitBool(marker: lookahead::TokenMarker) -> LitBool {
|
| 828 | match marker {}
|
| 829 | }
|
| 830 | }
|
| 831 |
|
| 832 | |
| 833 | |
| 834 | #[doc(hidden)] |
| 835 | pub enum StrStyle {
|
| 836 | |
| 837 | Cooked,
|
| 838 | |
| 839 | |
| 840 | |
| 841 | Raw(usize),
|
| 842 | }
|
| 843 |
|
| 844 | #[cfg(feature = "parsing")]
|
| 845 | pub_if_not_doc! {
|
| 846 | #[doc(hidden)]
|
| 847 | #[allow(non_snake_case)]
|
| 848 | pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
|
| 849 | match marker {}
|
| 850 | }
|
| 851 | }
|
| 852 |
|
| 853 | #[cfg(feature = "parsing")]
|
| 854 | pub(crate) mod parsing {
|
| 855 | use crate::buffer::Cursor;
|
| 856 | use crate::error::Result;
|
| 857 | use crate::lit::{
|
| 858 | value, Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitFloatRepr, LitInt,
|
| 859 | LitIntRepr, LitStr,
|
| 860 | };
|
| 861 | use crate::parse::{Parse, ParseStream, Unexpected};
|
| 862 | use crate::token::{self, Token};
|
| 863 | use proc_macro2::{Literal, Punct, Span};
|
| 864 | use std::cell::Cell;
|
| 865 | use std::rc::Rc;
|
| 866 |
|
| 867 | #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
| 868 | impl Parse for Lit {
|
| 869 | fn parse(input: ParseStream) -> Result<Self> {
|
| 870 | input.step(|cursor| {
|
| 871 | if let Some((lit, rest)) = cursor.literal() {
|
| 872 | return Ok((Lit::new(lit), rest));
|
| 873 | }
|
| 874 |
|
| 875 | if let Some((ident, rest)) = cursor.ident() {
|
| 876 | let value = ident == "true";
|
| 877 | if value || ident == "false" {
|
| 878 | let lit_bool = LitBool {
|
| 879 | value,
|
| 880 | span: ident.span(),
|
| 881 | };
|
| 882 | return Ok((Lit::Bool(lit_bool), rest));
|
| 883 | }
|
| 884 | }
|
| 885 |
|
| 886 | if let Some((punct, rest)) = cursor.punct() {
|
| 887 | if punct.as_char() == '-' {
|
| 888 | if let Some((lit, rest)) = parse_negative_lit(punct, rest) {
|
| 889 | return Ok((lit, rest));
|
| 890 | }
|
| 891 | }
|
| 892 | }
|
| 893 |
|
| 894 | Err(cursor.error("expected literal"))
|
| 895 | })
|
| 896 | }
|
| 897 | }
|
| 898 |
|
| 899 | fn parse_negative_lit(neg: Punct, cursor: Cursor) -> Option<(Lit, Cursor)> {
|
| 900 | let (lit, rest) = cursor.literal()?;
|
| 901 |
|
| 902 | let mut span = neg.span();
|
| 903 | span = span.join(lit.span()).unwrap_or(span);
|
| 904 |
|
| 905 | let mut repr = lit.to_string();
|
| 906 | repr.insert(0, '-');
|
| 907 |
|
| 908 | if let Some((digits, suffix)) = value::parse_lit_int(&repr) {
|
| 909 | let mut token: Literal = repr.parse().unwrap();
|
| 910 | token.set_span(span);
|
| 911 | return Some((
|
| 912 | Lit::Int(LitInt {
|
| 913 | repr: Box::new(LitIntRepr {
|
| 914 | token,
|
| 915 | digits,
|
| 916 | suffix,
|
| 917 | }),
|
| 918 | }),
|
| 919 | rest,
|
| 920 | ));
|
| 921 | }
|
| 922 |
|
| 923 | let (digits, suffix) = value::parse_lit_float(&repr)?;
|
| 924 | let mut token: Literal = repr.parse().unwrap();
|
| 925 | token.set_span(span);
|
| 926 | Some((
|
| 927 | Lit::Float(LitFloat {
|
| 928 | repr: Box::new(LitFloatRepr {
|
| 929 | token,
|
| 930 | digits,
|
| 931 | suffix,
|
| 932 | }),
|
| 933 | }),
|
| 934 | rest,
|
| 935 | ))
|
| 936 | }
|
| 937 |
|
| 938 | #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
| 939 | impl Parse for LitStr {
|
| 940 | fn parse(input: ParseStream) -> Result<Self> {
|
| 941 | let head = input.fork();
|
| 942 | match input.parse() {
|
| 943 | Ok(Lit::Str(lit)) => Ok(lit),
|
| 944 | _ => Err(head.error("expected string literal")),
|
| 945 | }
|
| 946 | }
|
| 947 | }
|
| 948 |
|
| 949 | #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
| 950 | impl Parse for LitByteStr {
|
| 951 | fn parse(input: ParseStream) -> Result<Self> {
|
| 952 | let head = input.fork();
|
| 953 | match input.parse() {
|
| 954 | Ok(Lit::ByteStr(lit)) => Ok(lit),
|
| 955 | _ => Err(head.error("expected byte string literal")),
|
| 956 | }
|
| 957 | }
|
| 958 | }
|
| 959 |
|
| 960 | #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
| 961 | impl Parse for LitCStr {
|
| 962 | fn parse(input: ParseStream) -> Result<Self> {
|
| 963 | let head = input.fork();
|
| 964 | match input.parse() {
|
| 965 | Ok(Lit::CStr(lit)) => Ok(lit),
|
| 966 | _ => Err(head.error("expected C string literal")),
|
| 967 | }
|
| 968 | }
|
| 969 | }
|
| 970 |
|
| 971 | #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
| 972 | impl Parse for LitByte {
|
| 973 | fn parse(input: ParseStream) -> Result<Self> {
|
| 974 | let head = input.fork();
|
| 975 | match input.parse() {
|
| 976 | Ok(Lit::Byte(lit)) => Ok(lit),
|
| 977 | _ => Err(head.error("expected byte literal")),
|
| 978 | }
|
| 979 | }
|
| 980 | }
|
| 981 |
|
| 982 | #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
| 983 | impl Parse for LitChar {
|
| 984 | fn parse(input: ParseStream) -> Result<Self> {
|
| 985 | let head = input.fork();
|
| 986 | match input.parse() {
|
| 987 | Ok(Lit::Char(lit)) => Ok(lit),
|
| 988 | _ => Err(head.error("expected character literal")),
|
| 989 | }
|
| 990 | }
|
| 991 | }
|
| 992 |
|
| 993 | #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
| 994 | impl Parse for LitInt {
|
| 995 | fn parse(input: ParseStream) -> Result<Self> {
|
| 996 | let head = input.fork();
|
| 997 | match input.parse() {
|
| 998 | Ok(Lit::Int(lit)) => Ok(lit),
|
| 999 | _ => Err(head.error("expected integer literal")),
|
| 1000 | }
|
| 1001 | }
|
| 1002 | }
|
| 1003 |
|
| 1004 | #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
| 1005 | impl Parse for LitFloat {
|
| 1006 | fn parse(input: ParseStream) -> Result<Self> {
|
| 1007 | let head = input.fork();
|
| 1008 | match input.parse() {
|
| 1009 | Ok(Lit::Float(lit)) => Ok(lit),
|
| 1010 | _ => Err(head.error("expected floating point literal")),
|
| 1011 | }
|
| 1012 | }
|
| 1013 | }
|
| 1014 |
|
| 1015 | #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
| 1016 | impl Parse for LitBool {
|
| 1017 | fn parse(input: ParseStream) -> Result<Self> {
|
| 1018 | let head = input.fork();
|
| 1019 | match input.parse() {
|
| 1020 | Ok(Lit::Bool(lit)) => Ok(lit),
|
| 1021 | _ => Err(head.error("expected boolean literal")),
|
| 1022 | }
|
| 1023 | }
|
| 1024 | }
|
| 1025 |
|
| 1026 | fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool {
|
| 1027 | let scope = Span::call_site();
|
| 1028 | let unexpected = Rc::new(Cell::new(Unexpected::None));
|
| 1029 | let buffer = crate::parse::new_parse_buffer(scope, cursor, unexpected);
|
| 1030 | peek(&buffer)
|
| 1031 | }
|
| 1032 |
|
| 1033 | macro_rules! impl_token {
|
| 1034 | ($display:literal $name:ty) => {
|
| 1035 | impl Token for $name {
|
| 1036 | fn peek(cursor: Cursor) -> bool {
|
| 1037 | fn peek(input: ParseStream) -> bool {
|
| 1038 | <$name as Parse>::parse(input).is_ok()
|
| 1039 | }
|
| 1040 | peek_impl(cursor, peek)
|
| 1041 | }
|
| 1042 |
|
| 1043 | fn display() -> &'static str {
|
| 1044 | $display
|
| 1045 | }
|
| 1046 | }
|
| 1047 |
|
| 1048 | impl token::private::Sealed for $name {}
|
| 1049 | };
|
| 1050 | }
|
| 1051 |
|
| 1052 | impl_token!("literal" Lit);
|
| 1053 | impl_token!("string literal" LitStr);
|
| 1054 | impl_token!("byte string literal" LitByteStr);
|
| 1055 | impl_token!("C-string literal" LitCStr);
|
| 1056 | impl_token!("byte literal" LitByte);
|
| 1057 | impl_token!("character literal" LitChar);
|
| 1058 | impl_token!("integer literal" LitInt);
|
| 1059 | impl_token!("floating point literal" LitFloat);
|
| 1060 | impl_token!("boolean literal" LitBool);
|
| 1061 | }
|
| 1062 |
|
| 1063 | #[cfg(feature = "printing")]
|
| 1064 | mod printing {
|
| 1065 | use crate::lit::{LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr};
|
| 1066 | use proc_macro2::TokenStream;
|
| 1067 | use quote::{ToTokens, TokenStreamExt};
|
| 1068 |
|
| 1069 | #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
| 1070 | impl ToTokens for LitStr {
|
| 1071 | fn to_tokens(&self, tokens: &mut TokenStream) {
|
| 1072 | self.repr.token.to_tokens(tokens);
|
| 1073 | }
|
| 1074 | }
|
| 1075 |
|
| 1076 | #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
| 1077 | impl ToTokens for LitByteStr {
|
| 1078 | fn to_tokens(&self, tokens: &mut TokenStream) {
|
| 1079 | self.repr.token.to_tokens(tokens);
|
| 1080 | }
|
| 1081 | }
|
| 1082 |
|
| 1083 | #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
| 1084 | impl ToTokens for LitCStr {
|
| 1085 | fn to_tokens(&self, tokens: &mut TokenStream) {
|
| 1086 | self.repr.token.to_tokens(tokens);
|
| 1087 | }
|
| 1088 | }
|
| 1089 |
|
| 1090 | #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
| 1091 | impl ToTokens for LitByte {
|
| 1092 | fn to_tokens(&self, tokens: &mut TokenStream) {
|
| 1093 | self.repr.token.to_tokens(tokens);
|
| 1094 | }
|
| 1095 | }
|
| 1096 |
|
| 1097 | #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
| 1098 | impl ToTokens for LitChar {
|
| 1099 | fn to_tokens(&self, tokens: &mut TokenStream) {
|
| 1100 | self.repr.token.to_tokens(tokens);
|
| 1101 | }
|
| 1102 | }
|
| 1103 |
|
| 1104 | #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
| 1105 | impl ToTokens for LitInt {
|
| 1106 | fn to_tokens(&self, tokens: &mut TokenStream) {
|
| 1107 | self.repr.token.to_tokens(tokens);
|
| 1108 | }
|
| 1109 | }
|
| 1110 |
|
| 1111 | #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
| 1112 | impl ToTokens for LitFloat {
|
| 1113 | fn to_tokens(&self, tokens: &mut TokenStream) {
|
| 1114 | self.repr.token.to_tokens(tokens);
|
| 1115 | }
|
| 1116 | }
|
| 1117 |
|
| 1118 | #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
| 1119 | impl ToTokens for LitBool {
|
| 1120 | fn to_tokens(&self, tokens: &mut TokenStream) {
|
| 1121 | tokens.append(self.token());
|
| 1122 | }
|
| 1123 | }
|
| 1124 | }
|
| 1125 |
|
| 1126 | mod value {
|
| 1127 | use crate::bigint::BigInt;
|
| 1128 | use crate::lit::{
|
| 1129 | Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitFloatRepr, LitInt,
|
| 1130 | LitIntRepr, LitRepr, LitStr,
|
| 1131 | };
|
| 1132 | use proc_macro2::{Literal, Span};
|
| 1133 | use std::ascii;
|
| 1134 | use std::char;
|
| 1135 | use std::ffi::CString;
|
| 1136 | use std::ops::{Index, RangeFrom};
|
| 1137 |
|
| 1138 | impl Lit {
|
| 1139 | |
| 1140 | pub fn new(token: Literal) -> Self {
|
| 1141 | let repr = token.to_string();
|
| 1142 |
|
| 1143 | match byte(&repr, 0) {
|
| 1144 | |
| 1145 | b'"' | b'r' => {
|
| 1146 | let (_, suffix) = parse_lit_str(&repr);
|
| 1147 | return Lit::Str(LitStr {
|
| 1148 | repr: Box::new(LitRepr { token, suffix }),
|
| 1149 | });
|
| 1150 | }
|
| 1151 | b'b' => match byte(&repr, 1) {
|
| 1152 | |
| 1153 | b'"' | b'r' => {
|
| 1154 | let (_, suffix) = parse_lit_byte_str(&repr);
|
| 1155 | return Lit::ByteStr(LitByteStr {
|
| 1156 | repr: Box::new(LitRepr { token, suffix }),
|
| 1157 | });
|
| 1158 | }
|
| 1159 | |
| 1160 | b'\'' => {
|
| 1161 | let (_, suffix) = parse_lit_byte(&repr);
|
| 1162 | return Lit::Byte(LitByte {
|
| 1163 | repr: Box::new(LitRepr { token, suffix }),
|
| 1164 | });
|
| 1165 | }
|
| 1166 | _ => {}
|
| 1167 | },
|
| 1168 | |
| 1169 | b'c' => {
|
| 1170 | let (_, suffix) = parse_lit_c_str(&repr);
|
| 1171 | return Lit::CStr(LitCStr {
|
| 1172 | repr: Box::new(LitRepr { token, suffix }),
|
| 1173 | });
|
| 1174 | }
|
| 1175 | |
| 1176 | b'\'' => {
|
| 1177 | let (_, suffix) = parse_lit_char(&repr);
|
| 1178 | return Lit::Char(LitChar {
|
| 1179 | repr: Box::new(LitRepr { token, suffix }),
|
| 1180 | });
|
| 1181 | }
|
| 1182 | b'0'..=b'9' | b'-' => {
|
| 1183 | |
| 1184 | if let Some((digits, suffix)) = parse_lit_int(&repr) {
|
| 1185 | return Lit::Int(LitInt {
|
| 1186 | repr: Box::new(LitIntRepr {
|
| 1187 | token,
|
| 1188 | digits,
|
| 1189 | suffix,
|
| 1190 | }),
|
| 1191 | });
|
| 1192 | }
|
| 1193 | |
| 1194 | if let Some((digits, suffix)) = parse_lit_float(&repr) {
|
| 1195 | return Lit::Float(LitFloat {
|
| 1196 | repr: Box::new(LitFloatRepr {
|
| 1197 | token,
|
| 1198 | digits,
|
| 1199 | suffix,
|
| 1200 | }),
|
| 1201 | });
|
| 1202 | }
|
| 1203 | }
|
| 1204 | |
| 1205 | b't' | b'f' => {
|
| 1206 | if repr == "true" || repr == "false" {
|
| 1207 | return Lit::Bool(LitBool {
|
| 1208 | value: repr == "true",
|
| 1209 | span: token.span(),
|
| 1210 | });
|
| 1211 | }
|
| 1212 | }
|
| 1213 | b'(' if repr == "(/*ERROR*/)" => return Lit::Verbatim(token),
|
| 1214 | _ => {}
|
| 1215 | }
|
| 1216 |
|
| 1217 | panic!("unrecognized literal: `{}`", repr);
|
| 1218 | }
|
| 1219 |
|
| 1220 | pub fn suffix(&self) -> &str {
|
| 1221 | match self {
|
| 1222 | Lit::Str(lit) => lit.suffix(),
|
| 1223 | Lit::ByteStr(lit) => lit.suffix(),
|
| 1224 | Lit::CStr(lit) => lit.suffix(),
|
| 1225 | Lit::Byte(lit) => lit.suffix(),
|
| 1226 | Lit::Char(lit) => lit.suffix(),
|
| 1227 | Lit::Int(lit) => lit.suffix(),
|
| 1228 | Lit::Float(lit) => lit.suffix(),
|
| 1229 | Lit::Bool(_) | Lit::Verbatim(_) => "",
|
| 1230 | }
|
| 1231 | }
|
| 1232 |
|
| 1233 | pub fn span(&self) -> Span {
|
| 1234 | match self {
|
| 1235 | Lit::Str(lit) => lit.span(),
|
| 1236 | Lit::ByteStr(lit) => lit.span(),
|
| 1237 | Lit::CStr(lit) => lit.span(),
|
| 1238 | Lit::Byte(lit) => lit.span(),
|
| 1239 | Lit::Char(lit) => lit.span(),
|
| 1240 | Lit::Int(lit) => lit.span(),
|
| 1241 | Lit::Float(lit) => lit.span(),
|
| 1242 | Lit::Bool(lit) => lit.span,
|
| 1243 | Lit::Verbatim(lit) => lit.span(),
|
| 1244 | }
|
| 1245 | }
|
| 1246 |
|
| 1247 | pub fn set_span(&mut self, span: Span) {
|
| 1248 | match self {
|
| 1249 | Lit::Str(lit) => lit.set_span(span),
|
| 1250 | Lit::ByteStr(lit) => lit.set_span(span),
|
| 1251 | Lit::CStr(lit) => lit.set_span(span),
|
| 1252 | Lit::Byte(lit) => lit.set_span(span),
|
| 1253 | Lit::Char(lit) => lit.set_span(span),
|
| 1254 | Lit::Int(lit) => lit.set_span(span),
|
| 1255 | Lit::Float(lit) => lit.set_span(span),
|
| 1256 | Lit::Bool(lit) => lit.span = span,
|
| 1257 | Lit::Verbatim(lit) => lit.set_span(span),
|
| 1258 | }
|
| 1259 | }
|
| 1260 | }
|
| 1261 |
|
| 1262 | |
| 1263 | |
| 1264 | pub(crate) fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
|
| 1265 | let s = s.as_ref();
|
| 1266 | if idx < s.len() {
|
| 1267 | s[idx]
|
| 1268 | } else {
|
| 1269 | 0
|
| 1270 | }
|
| 1271 | }
|
| 1272 |
|
| 1273 | fn next_chr(s: &str) -> char {
|
| 1274 | s.chars().next().unwrap_or('\0')
|
| 1275 | }
|
| 1276 |
|
| 1277 | |
| 1278 | pub(crate) fn parse_lit_str(s: &str) -> (Box<str>, Box<str>) {
|
| 1279 | match byte(s, 0) {
|
| 1280 | b'"' => parse_lit_str_cooked(s),
|
| 1281 | b'r' => parse_lit_str_raw(s),
|
| 1282 | _ => unreachable!(),
|
| 1283 | }
|
| 1284 | }
|
| 1285 |
|
| 1286 | fn parse_lit_str_cooked(mut s: &str) -> (Box<str>, Box<str>) {
|
| 1287 | assert_eq!(byte(s, 0), b'"');
|
| 1288 | s = &s[1..];
|
| 1289 |
|
| 1290 | let mut content = String::new();
|
| 1291 | 'outer: loop {
|
| 1292 | let ch = match byte(s, 0) {
|
| 1293 | b'"' => break,
|
| 1294 | b'\\' => {
|
| 1295 | let b = byte(s, 1);
|
| 1296 | s = &s[2..];
|
| 1297 | match b {
|
| 1298 | b'x' => {
|
| 1299 | let (byte, rest) = backslash_x(s);
|
| 1300 | s = rest;
|
| 1301 | assert!(byte <= 0x7F, "invalid \\x byte in string literal");
|
| 1302 | char::from_u32(u32::from(byte)).unwrap()
|
| 1303 | }
|
| 1304 | b'u' => {
|
| 1305 | let (ch, rest) = backslash_u(s);
|
| 1306 | s = rest;
|
| 1307 | ch
|
| 1308 | }
|
| 1309 | b'n' => '\n',
|
| 1310 | b'r' => '\r',
|
| 1311 | b't' => '\t',
|
| 1312 | b'\\' => '\\',
|
| 1313 | b'0' => '\0',
|
| 1314 | b'\'' => '\'',
|
| 1315 | b'"' => '"',
|
| 1316 | b'\r' | b'\n' => loop {
|
| 1317 | let b = byte(s, 0);
|
| 1318 | match b {
|
| 1319 | b' ' | b'\t' | b'\n' | b'\r' => s = &s[1..],
|
| 1320 | _ => continue 'outer,
|
| 1321 | }
|
| 1322 | },
|
| 1323 | b => panic!(
|
| 1324 | "unexpected byte '{}' after \\ character in string literal",
|
| 1325 | ascii::escape_default(b),
|
| 1326 | ),
|
| 1327 | }
|
| 1328 | }
|
| 1329 | b'\r' => {
|
| 1330 | assert_eq!(byte(s, 1), b'\n', "bare CR not allowed in string");
|
| 1331 | s = &s[2..];
|
| 1332 | '\n'
|
| 1333 | }
|
| 1334 | _ => {
|
| 1335 | let ch = next_chr(s);
|
| 1336 | s = &s[ch.len_utf8()..];
|
| 1337 | ch
|
| 1338 | }
|
| 1339 | };
|
| 1340 | content.push(ch);
|
| 1341 | }
|
| 1342 |
|
| 1343 | assert!(s.starts_with('"'));
|
| 1344 | let content = content.into_boxed_str();
|
| 1345 | let suffix = s[1..].to_owned().into_boxed_str();
|
| 1346 | (content, suffix)
|
| 1347 | }
|
| 1348 |
|
| 1349 | fn parse_lit_str_raw(mut s: &str) -> (Box<str>, Box<str>) {
|
| 1350 | assert_eq!(byte(s, 0), b'r');
|
| 1351 | s = &s[1..];
|
| 1352 |
|
| 1353 | let mut pounds = 0;
|
| 1354 | while byte(s, pounds) == b'#' {
|
| 1355 | pounds += 1;
|
| 1356 | }
|
| 1357 | assert_eq!(byte(s, pounds), b'"');
|
| 1358 | let close = s.rfind('"').unwrap();
|
| 1359 | for end in s[close + 1..close + 1 + pounds].bytes() {
|
| 1360 | assert_eq!(end, b'#');
|
| 1361 | }
|
| 1362 |
|
| 1363 | let content = s[pounds + 1..close].to_owned().into_boxed_str();
|
| 1364 | let suffix = s[close + 1 + pounds..].to_owned().into_boxed_str();
|
| 1365 | (content, suffix)
|
| 1366 | }
|
| 1367 |
|
| 1368 | |
| 1369 | pub(crate) fn parse_lit_byte_str(s: &str) -> (Vec<u8>, Box<str>) {
|
| 1370 | assert_eq!(byte(s, 0), b'b');
|
| 1371 | match byte(s, 1) {
|
| 1372 | b'"' => parse_lit_byte_str_cooked(s),
|
| 1373 | b'r' => parse_lit_byte_str_raw(s),
|
| 1374 | _ => unreachable!(),
|
| 1375 | }
|
| 1376 | }
|
| 1377 |
|
| 1378 | fn parse_lit_byte_str_cooked(mut s: &str) -> (Vec<u8>, Box<str>) {
|
| 1379 | assert_eq!(byte(s, 0), b'b');
|
| 1380 | assert_eq!(byte(s, 1), b'"');
|
| 1381 | s = &s[2..];
|
| 1382 |
|
| 1383 | |
| 1384 | let mut v = s.as_bytes();
|
| 1385 |
|
| 1386 | let mut out = Vec::new();
|
| 1387 | 'outer: loop {
|
| 1388 | let byte = match byte(v, 0) {
|
| 1389 | b'"' => break,
|
| 1390 | b'\\' => {
|
| 1391 | let b = byte(v, 1);
|
| 1392 | v = &v[2..];
|
| 1393 | match b {
|
| 1394 | b'x' => {
|
| 1395 | let (b, rest) = backslash_x(v);
|
| 1396 | v = rest;
|
| 1397 | b
|
| 1398 | }
|
| 1399 | b'n' => b'\n',
|
| 1400 | b'r' => b'\r',
|
| 1401 | b't' => b'\t',
|
| 1402 | b'\\' => b'\\',
|
| 1403 | b'0' => b'\0',
|
| 1404 | b'\'' => b'\'',
|
| 1405 | b'"' => b'"',
|
| 1406 | b'\r' | b'\n' => loop {
|
| 1407 | let byte = byte(v, 0);
|
| 1408 | if matches!(byte, b' ' | b'\t' | b'\n' | b'\r') {
|
| 1409 | v = &v[1..];
|
| 1410 | } else {
|
| 1411 | continue 'outer;
|
| 1412 | }
|
| 1413 | },
|
| 1414 | b => panic!(
|
| 1415 | "unexpected byte '{}' after \\ character in byte-string literal",
|
| 1416 | ascii::escape_default(b),
|
| 1417 | ),
|
| 1418 | }
|
| 1419 | }
|
| 1420 | b'\r' => {
|
| 1421 | assert_eq!(byte(v, 1), b'\n', "bare CR not allowed in string");
|
| 1422 | v = &v[2..];
|
| 1423 | b'\n'
|
| 1424 | }
|
| 1425 | b => {
|
| 1426 | v = &v[1..];
|
| 1427 | b
|
| 1428 | }
|
| 1429 | };
|
| 1430 | out.push(byte);
|
| 1431 | }
|
| 1432 |
|
| 1433 | assert_eq!(byte(v, 0), b'"');
|
| 1434 | let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
|
| 1435 | (out, suffix)
|
| 1436 | }
|
| 1437 |
|
| 1438 | fn parse_lit_byte_str_raw(s: &str) -> (Vec<u8>, Box<str>) {
|
| 1439 | assert_eq!(byte(s, 0), b'b');
|
| 1440 | let (value, suffix) = parse_lit_str_raw(&s[1..]);
|
| 1441 | (String::from(value).into_bytes(), suffix)
|
| 1442 | }
|
| 1443 |
|
| 1444 | |
| 1445 | pub(crate) fn parse_lit_c_str(s: &str) -> (CString, Box<str>) {
|
| 1446 | assert_eq!(byte(s, 0), b'c');
|
| 1447 | match byte(s, 1) {
|
| 1448 | b'"' => parse_lit_c_str_cooked(s),
|
| 1449 | b'r' => parse_lit_c_str_raw(s),
|
| 1450 | _ => unreachable!(),
|
| 1451 | }
|
| 1452 | }
|
| 1453 |
|
| 1454 | fn parse_lit_c_str_cooked(mut s: &str) -> (CString, Box<str>) {
|
| 1455 | assert_eq!(byte(s, 0), b'c');
|
| 1456 | assert_eq!(byte(s, 1), b'"');
|
| 1457 | s = &s[2..];
|
| 1458 |
|
| 1459 | |
| 1460 | let mut v = s.as_bytes();
|
| 1461 |
|
| 1462 | let mut out = Vec::new();
|
| 1463 | 'outer: loop {
|
| 1464 | let byte = match byte(v, 0) {
|
| 1465 | b'"' => break,
|
| 1466 | b'\\' => {
|
| 1467 | let b = byte(v, 1);
|
| 1468 | v = &v[2..];
|
| 1469 | match b {
|
| 1470 | b'x' => {
|
| 1471 | let (b, rest) = backslash_x(v);
|
| 1472 | assert!(b != 0, "\\x00 is not allowed in C-string literal");
|
| 1473 | v = rest;
|
| 1474 | b
|
| 1475 | }
|
| 1476 | b'u' => {
|
| 1477 | let (ch, rest) = backslash_u(v);
|
| 1478 | assert!(ch != '\0', "\\u{{0}} is not allowed in C-string literal");
|
| 1479 | v = rest;
|
| 1480 | out.extend_from_slice(ch.encode_utf8(&mut [0u8; 4]).as_bytes());
|
| 1481 | continue 'outer;
|
| 1482 | }
|
| 1483 | b'n' => b'\n',
|
| 1484 | b'r' => b'\r',
|
| 1485 | b't' => b'\t',
|
| 1486 | b'\\' => b'\\',
|
| 1487 | b'\'' => b'\'',
|
| 1488 | b'"' => b'"',
|
| 1489 | b'\r' | b'\n' => loop {
|
| 1490 | let byte = byte(v, 0);
|
| 1491 | if matches!(byte, b' ' | b'\t' | b'\n' | b'\r') {
|
| 1492 | v = &v[1..];
|
| 1493 | } else {
|
| 1494 | continue 'outer;
|
| 1495 | }
|
| 1496 | },
|
| 1497 | b => panic!(
|
| 1498 | "unexpected byte '{}' after \\ character in byte literal",
|
| 1499 | ascii::escape_default(b),
|
| 1500 | ),
|
| 1501 | }
|
| 1502 | }
|
| 1503 | b'\r' => {
|
| 1504 | assert_eq!(byte(v, 1), b'\n', "bare CR not allowed in string");
|
| 1505 | v = &v[2..];
|
| 1506 | b'\n'
|
| 1507 | }
|
| 1508 | b => {
|
| 1509 | v = &v[1..];
|
| 1510 | b
|
| 1511 | }
|
| 1512 | };
|
| 1513 | out.push(byte);
|
| 1514 | }
|
| 1515 |
|
| 1516 | assert_eq!(byte(v, 0), b'"');
|
| 1517 | let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
|
| 1518 | (CString::new(out).unwrap(), suffix)
|
| 1519 | }
|
| 1520 |
|
| 1521 | fn parse_lit_c_str_raw(s: &str) -> (CString, Box<str>) {
|
| 1522 | assert_eq!(byte(s, 0), b'c');
|
| 1523 | let (value, suffix) = parse_lit_str_raw(&s[1..]);
|
| 1524 | (CString::new(String::from(value)).unwrap(), suffix)
|
| 1525 | }
|
| 1526 |
|
| 1527 | |
| 1528 | pub(crate) fn parse_lit_byte(s: &str) -> (u8, Box<str>) {
|
| 1529 | assert_eq!(byte(s, 0), b'b');
|
| 1530 | assert_eq!(byte(s, 1), b'\'');
|
| 1531 |
|
| 1532 | |
| 1533 | let mut v = &s.as_bytes()[2..];
|
| 1534 |
|
| 1535 | let b = match byte(v, 0) {
|
| 1536 | b'\\' => {
|
| 1537 | let b = byte(v, 1);
|
| 1538 | v = &v[2..];
|
| 1539 | match b {
|
| 1540 | b'x' => {
|
| 1541 | let (b, rest) = backslash_x(v);
|
| 1542 | v = rest;
|
| 1543 | b
|
| 1544 | }
|
| 1545 | b'n' => b'\n',
|
| 1546 | b'r' => b'\r',
|
| 1547 | b't' => b'\t',
|
| 1548 | b'\\' => b'\\',
|
| 1549 | b'0' => b'\0',
|
| 1550 | b'\'' => b'\'',
|
| 1551 | b'"' => b'"',
|
| 1552 | b => panic!(
|
| 1553 | "unexpected byte '{}' after \\ character in byte literal",
|
| 1554 | ascii::escape_default(b),
|
| 1555 | ),
|
| 1556 | }
|
| 1557 | }
|
| 1558 | b => {
|
| 1559 | v = &v[1..];
|
| 1560 | b
|
| 1561 | }
|
| 1562 | };
|
| 1563 |
|
| 1564 | assert_eq!(byte(v, 0), b'\'');
|
| 1565 | let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
|
| 1566 | (b, suffix)
|
| 1567 | }
|
| 1568 |
|
| 1569 | |
| 1570 | pub(crate) fn parse_lit_char(mut s: &str) -> (char, Box<str>) {
|
| 1571 | assert_eq!(byte(s, 0), b'\'');
|
| 1572 | s = &s[1..];
|
| 1573 |
|
| 1574 | let ch = match byte(s, 0) {
|
| 1575 | b'\\' => {
|
| 1576 | let b = byte(s, 1);
|
| 1577 | s = &s[2..];
|
| 1578 | match b {
|
| 1579 | b'x' => {
|
| 1580 | let (byte, rest) = backslash_x(s);
|
| 1581 | s = rest;
|
| 1582 | assert!(byte <= 0x7F, "invalid \\x byte in character literal");
|
| 1583 | char::from_u32(u32::from(byte)).unwrap()
|
| 1584 | }
|
| 1585 | b'u' => {
|
| 1586 | let (ch, rest) = backslash_u(s);
|
| 1587 | s = rest;
|
| 1588 | ch
|
| 1589 | }
|
| 1590 | b'n' => '\n',
|
| 1591 | b'r' => '\r',
|
| 1592 | b't' => '\t',
|
| 1593 | b'\\' => '\\',
|
| 1594 | b'0' => '\0',
|
| 1595 | b'\'' => '\'',
|
| 1596 | b'"' => '"',
|
| 1597 | b => panic!(
|
| 1598 | "unexpected byte '{}' after \\ character in character literal",
|
| 1599 | ascii::escape_default(b),
|
| 1600 | ),
|
| 1601 | }
|
| 1602 | }
|
| 1603 | _ => {
|
| 1604 | let ch = next_chr(s);
|
| 1605 | s = &s[ch.len_utf8()..];
|
| 1606 | ch
|
| 1607 | }
|
| 1608 | };
|
| 1609 | assert_eq!(byte(s, 0), b'\'');
|
| 1610 | let suffix = s[1..].to_owned().into_boxed_str();
|
| 1611 | (ch, suffix)
|
| 1612 | }
|
| 1613 |
|
| 1614 | fn backslash_x<S>(s: &S) -> (u8, &S)
|
| 1615 | where
|
| 1616 | S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
|
| 1617 | {
|
| 1618 | let mut ch = 0;
|
| 1619 | let b0 = byte(s, 0);
|
| 1620 | let b1 = byte(s, 1);
|
| 1621 | ch += 0x10
|
| 1622 | * match b0 {
|
| 1623 | b'0'..=b'9' => b0 - b'0',
|
| 1624 | b'a'..=b'f' => 10 + (b0 - b'a'),
|
| 1625 | b'A'..=b'F' => 10 + (b0 - b'A'),
|
| 1626 | _ => panic!("unexpected non-hex character after \\x"),
|
| 1627 | };
|
| 1628 | ch += match b1 {
|
| 1629 | b'0'..=b'9' => b1 - b'0',
|
| 1630 | b'a'..=b'f' => 10 + (b1 - b'a'),
|
| 1631 | b'A'..=b'F' => 10 + (b1 - b'A'),
|
| 1632 | _ => panic!("unexpected non-hex character after \\x"),
|
| 1633 | };
|
| 1634 | (ch, &s[2..])
|
| 1635 | }
|
| 1636 |
|
| 1637 | fn backslash_u<S>(mut s: &S) -> (char, &S)
|
| 1638 | where
|
| 1639 | S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
|
| 1640 | {
|
| 1641 | if byte(s, 0) != b'{' {
|
| 1642 | panic!("{}", "expected { after \\u");
|
| 1643 | }
|
| 1644 | s = &s[1..];
|
| 1645 |
|
| 1646 | let mut ch = 0;
|
| 1647 | let mut digits = 0;
|
| 1648 | loop {
|
| 1649 | let b = byte(s, 0);
|
| 1650 | let digit = match b {
|
| 1651 | b'0'..=b'9' => b - b'0',
|
| 1652 | b'a'..=b'f' => 10 + b - b'a',
|
| 1653 | b'A'..=b'F' => 10 + b - b'A',
|
| 1654 | b'_' if digits > 0 => {
|
| 1655 | s = &s[1..];
|
| 1656 | continue;
|
| 1657 | }
|
| 1658 | b'}' if digits == 0 => panic!("invalid empty unicode escape"),
|
| 1659 | b'}' => break,
|
| 1660 | _ => panic!("unexpected non-hex character after \\u"),
|
| 1661 | };
|
| 1662 | if digits == 6 {
|
| 1663 | panic!("overlong unicode escape (must have at most 6 hex digits)");
|
| 1664 | }
|
| 1665 | ch *= 0x10;
|
| 1666 | ch += u32::from(digit);
|
| 1667 | digits += 1;
|
| 1668 | s = &s[1..];
|
| 1669 | }
|
| 1670 | assert!(byte(s, 0) == b'}');
|
| 1671 | s = &s[1..];
|
| 1672 |
|
| 1673 | if let Some(ch) = char::from_u32(ch) {
|
| 1674 | (ch, s)
|
| 1675 | } else {
|
| 1676 | panic!("character code {:x} is not a valid unicode character", ch);
|
| 1677 | }
|
| 1678 | }
|
| 1679 |
|
| 1680 | |
| 1681 | pub(crate) fn parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)> {
|
| 1682 | let negative = byte(s, 0) == b'-';
|
| 1683 | if negative {
|
| 1684 | s = &s[1..];
|
| 1685 | }
|
| 1686 |
|
| 1687 | let base = match (byte(s, 0), byte(s, 1)) {
|
| 1688 | (b'0', b'x') => {
|
| 1689 | s = &s[2..];
|
| 1690 | 16
|
| 1691 | }
|
| 1692 | (b'0', b'o') => {
|
| 1693 | s = &s[2..];
|
| 1694 | 8
|
| 1695 | }
|
| 1696 | (b'0', b'b') => {
|
| 1697 | s = &s[2..];
|
| 1698 | 2
|
| 1699 | }
|
| 1700 | (b'0'..=b'9', _) => 10,
|
| 1701 | _ => return None,
|
| 1702 | };
|
| 1703 |
|
| 1704 | let mut value = BigInt::new();
|
| 1705 | let mut has_digit = false;
|
| 1706 | 'outer: loop {
|
| 1707 | let b = byte(s, 0);
|
| 1708 | let digit = match b {
|
| 1709 | b'0'..=b'9' => b - b'0',
|
| 1710 | b'a'..=b'f' if base > 10 => b - b'a' + 10,
|
| 1711 | b'A'..=b'F' if base > 10 => b - b'A' + 10,
|
| 1712 | b'_' => {
|
| 1713 | s = &s[1..];
|
| 1714 | continue;
|
| 1715 | }
|
| 1716 | |
| 1717 | |
| 1718 | b'.' if base == 10 => return None,
|
| 1719 | b'e' | b'E' if base == 10 => {
|
| 1720 | let mut has_exp = false;
|
| 1721 | for (i, b) in s[1..].bytes().enumerate() {
|
| 1722 | match b {
|
| 1723 | b'_' => {}
|
| 1724 | b'-' | b'+' => return None,
|
| 1725 | b'0'..=b'9' => has_exp = true,
|
| 1726 | _ => {
|
| 1727 | let suffix = &s[1 + i..];
|
| 1728 | if has_exp && crate::ident::xid_ok(suffix) {
|
| 1729 | return None;
|
| 1730 | } else {
|
| 1731 | break 'outer;
|
| 1732 | }
|
| 1733 | }
|
| 1734 | }
|
| 1735 | }
|
| 1736 | if has_exp {
|
| 1737 | return None;
|
| 1738 | } else {
|
| 1739 | break;
|
| 1740 | }
|
| 1741 | }
|
| 1742 | _ => break,
|
| 1743 | };
|
| 1744 |
|
| 1745 | if digit >= base {
|
| 1746 | return None;
|
| 1747 | }
|
| 1748 |
|
| 1749 | has_digit = true;
|
| 1750 | value *= base;
|
| 1751 | value += digit;
|
| 1752 | s = &s[1..];
|
| 1753 | }
|
| 1754 |
|
| 1755 | if !has_digit {
|
| 1756 | return None;
|
| 1757 | }
|
| 1758 |
|
| 1759 | let suffix = s;
|
| 1760 | if suffix.is_empty() || crate::ident::xid_ok(suffix) {
|
| 1761 | let mut repr = value.to_string();
|
| 1762 | if negative {
|
| 1763 | repr.insert(0, '-');
|
| 1764 | }
|
| 1765 | Some((repr.into_boxed_str(), suffix.to_owned().into_boxed_str()))
|
| 1766 | } else {
|
| 1767 | None
|
| 1768 | }
|
| 1769 | }
|
| 1770 |
|
| 1771 | |
| 1772 | pub(crate) fn parse_lit_float(input: &str) -> Option<(Box<str>, Box<str>)> {
|
| 1773 | |
| 1774 | |
| 1775 | |
| 1776 |
|
| 1777 | let mut bytes = input.to_owned().into_bytes();
|
| 1778 |
|
| 1779 | let start = (*bytes.first()? == b'-') as usize;
|
| 1780 | match bytes.get(start)? {
|
| 1781 | b'0'..=b'9' => {}
|
| 1782 | _ => return None,
|
| 1783 | }
|
| 1784 |
|
| 1785 | let mut read = start;
|
| 1786 | let mut write = start;
|
| 1787 | let mut has_dot = false;
|
| 1788 | let mut has_e = false;
|
| 1789 | let mut has_sign = false;
|
| 1790 | let mut has_exponent = false;
|
| 1791 | while read < bytes.len() {
|
| 1792 | match bytes[read] {
|
| 1793 | b'_' => {
|
| 1794 | |
| 1795 | read += 1;
|
| 1796 | continue;
|
| 1797 | }
|
| 1798 | b'0'..=b'9' => {
|
| 1799 | if has_e {
|
| 1800 | has_exponent = true;
|
| 1801 | }
|
| 1802 | bytes[write] = bytes[read];
|
| 1803 | }
|
| 1804 | b'.' => {
|
| 1805 | if has_e || has_dot {
|
| 1806 | return None;
|
| 1807 | }
|
| 1808 | has_dot = true;
|
| 1809 | bytes[write] = b'.';
|
| 1810 | }
|
| 1811 | b'e' | b'E' => {
|
| 1812 | match bytes[read + 1..]
|
| 1813 | .iter()
|
| 1814 | .find(|b| **b != b'_')
|
| 1815 | .unwrap_or(&b'\0')
|
| 1816 | {
|
| 1817 | b'-' | b'+' | b'0'..=b'9' => {}
|
| 1818 | _ => break,
|
| 1819 | }
|
| 1820 | if has_e {
|
| 1821 | if has_exponent {
|
| 1822 | break;
|
| 1823 | } else {
|
| 1824 | return None;
|
| 1825 | }
|
| 1826 | }
|
| 1827 | has_e = true;
|
| 1828 | bytes[write] = b'e';
|
| 1829 | }
|
| 1830 | b'-' | b'+' => {
|
| 1831 | if has_sign || has_exponent || !has_e {
|
| 1832 | return None;
|
| 1833 | }
|
| 1834 | has_sign = true;
|
| 1835 | if bytes[read] == b'-' {
|
| 1836 | bytes[write] = bytes[read];
|
| 1837 | } else {
|
| 1838 | |
| 1839 | read += 1;
|
| 1840 | continue;
|
| 1841 | }
|
| 1842 | }
|
| 1843 | _ => break,
|
| 1844 | }
|
| 1845 | read += 1;
|
| 1846 | write += 1;
|
| 1847 | }
|
| 1848 |
|
| 1849 | if has_e && !has_exponent {
|
| 1850 | return None;
|
| 1851 | }
|
| 1852 |
|
| 1853 | let mut digits = String::from_utf8(bytes).unwrap();
|
| 1854 | let suffix = digits.split_off(read);
|
| 1855 | digits.truncate(write);
|
| 1856 | if suffix.is_empty() || crate::ident::xid_ok(&suffix) {
|
| 1857 | Some((digits.into_boxed_str(), suffix.into_boxed_str()))
|
| 1858 | } else {
|
| 1859 | None
|
| 1860 | }
|
| 1861 | }
|
| 1862 | }
|