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