blob: cf1e062af46ed3643eccbdfd5a56a785b1838fd9 [file] [log] [blame]
David Tolnay360efd22018-01-04 23:35:26 -08001use proc_macro2::{Literal, Span, Term, TokenNode, TokenTree};
2use std::str;
3
4#[cfg(feature = "extra-traits")]
Alex Crichtonccbb45d2017-05-23 10:58:24 -07005use std::hash::{Hash, Hasher};
6
David Tolnay360efd22018-01-04 23:35:26 -08007ast_enum_of_structs! {
8 pub enum Lit {
9 /// A string literal (`"foo"`)
10 pub Str(LitStr #manual_extra_traits {
11 token: Literal,
12 pub span: Span,
13 }),
Alex Crichtonccbb45d2017-05-23 10:58:24 -070014
David Tolnay360efd22018-01-04 23:35:26 -080015 /// A byte string (`b"foo"`)
16 pub ByteStr(LitByteStr #manual_extra_traits {
17 token: Literal,
18 pub span: Span,
19 }),
20
21 /// A byte char (`b'f'`)
22 pub Byte(LitByte #manual_extra_traits {
23 token: Literal,
24 pub span: Span,
25 }),
26
27 /// A character literal (`'a'`)
28 pub Char(LitChar #manual_extra_traits {
29 token: Literal,
30 pub span: Span,
31 }),
32
33 /// An integer literal (`1`)
34 ///
35 /// Holds up to 64 bits of data. Use `LitVerbatim` for any larger
36 /// integer literal.
37 pub Int(LitInt #manual_extra_traits {
38 token: Literal,
39 pub span: Span,
40 }),
41
42 /// A float literal (`1f64` or `1E10f64`)
43 ///
44 /// Must be finite. May not be infinte or NaN.
45 pub Float(LitFloat #manual_extra_traits {
46 token: Literal,
47 pub span: Span,
48 }),
49
50 /// A boolean literal
51 pub Bool(LitBool #manual_extra_traits {
52 pub value: bool,
53 pub span: Span,
54 }),
55
56 pub Verbatim(LitVerbatim #manual_extra_traits {
57 pub token: Literal,
58 pub span: Span,
59 }),
60 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -070061}
62
David Tolnay360efd22018-01-04 23:35:26 -080063impl LitStr {
64 pub fn new(value: &str, span: Span) -> Self {
65 LitStr {
66 token: Literal::string(value),
67 span: span,
68 }
69 }
70
71 pub fn value(&self) -> String {
72 value::parse_lit_str(&self.token.to_string())
73 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -070074}
75
David Tolnay360efd22018-01-04 23:35:26 -080076impl LitByteStr {
77 pub fn new(value: &[u8], span: Span) -> Self {
78 LitByteStr {
79 token: Literal::byte_string(value),
80 span: span,
81 }
82 }
83
84 pub fn value(&self) -> Vec<u8> {
85 value::parse_lit_byte_str(&self.token.to_string())
86 }
87}
88
89impl LitByte {
90 pub fn new(value: u8, span: Span) -> Self {
91 LitByte {
92 token: Literal::byte_char(value),
93 span: span,
94 }
95 }
96
97 pub fn value(&self) -> u8 {
98 value::parse_lit_byte(&self.token.to_string())
99 }
100}
101
102impl LitChar {
103 pub fn new(value: char, span: Span) -> Self {
104 LitChar {
105 token: Literal::character(value),
106 span: span,
107 }
108 }
109
110 pub fn value(&self) -> char {
111 value::parse_lit_char(&self.token.to_string())
112 }
113}
114
115impl LitInt {
116 pub fn new(value: u64, suffix: IntSuffix, span: Span) -> Self {
117 LitInt {
118 token: match suffix {
119 IntSuffix::Isize => Literal::isize(value as isize),
120 IntSuffix::I8 => Literal::i8(value as i8),
121 IntSuffix::I16 => Literal::i16(value as i16),
122 IntSuffix::I32 => Literal::i32(value as i32),
123 IntSuffix::I64 => Literal::i64(value as i64),
124 IntSuffix::I128 => value::to_literal(&format!("{}i128", value)),
125 IntSuffix::Usize => Literal::usize(value as usize),
126 IntSuffix::U8 => Literal::u8(value as u8),
127 IntSuffix::U16 => Literal::u16(value as u16),
128 IntSuffix::U32 => Literal::u32(value as u32),
129 IntSuffix::U64 => Literal::u64(value),
130 IntSuffix::U128 => value::to_literal(&format!("{}u128", value)),
131 IntSuffix::None => Literal::integer(value as i64),
132 },
133 span: span,
134 }
135 }
136
137 pub fn value(&self) -> u64 {
138 value::parse_lit_int(&self.token.to_string()).unwrap()
139 }
140
141 pub fn suffix(&self) -> IntSuffix {
142 let value = self.token.to_string();
143 for (s, suffix) in vec![
144 ("i8", IntSuffix::I8),
145 ("i16", IntSuffix::I16),
146 ("i32", IntSuffix::I32),
147 ("i64", IntSuffix::I64),
148 ("i128", IntSuffix::I128),
149 ("isize", IntSuffix::Isize),
150 ("u8", IntSuffix::U8),
151 ("u16", IntSuffix::U16),
152 ("u32", IntSuffix::U32),
153 ("u64", IntSuffix::U64),
154 ("u128", IntSuffix::U128),
155 ("usize", IntSuffix::Usize),
156 ] {
157 if value.ends_with(s) {
158 return suffix;
159 }
160 }
161 IntSuffix::None
162 }
163}
164
165impl LitFloat {
166 pub fn new(value: f64, suffix: FloatSuffix, span: Span) -> Self {
167 LitFloat {
168 token: match suffix {
169 FloatSuffix::F32 => Literal::f32(value as f32),
170 FloatSuffix::F64 => Literal::f64(value),
171 FloatSuffix::None => Literal::float(value),
172 },
173 span: span,
174 }
175 }
176
177 pub fn value(&self) -> f64 {
178 value::parse_lit_float(&self.token.to_string())
179 }
180
181 pub fn suffix(&self) -> FloatSuffix {
182 let value = self.token.to_string();
183 for (s, suffix) in vec![
184 ("f32", FloatSuffix::F32),
185 ("f64", FloatSuffix::F64),
186 ] {
187 if value.ends_with(s) {
188 return suffix;
189 }
190 }
191 FloatSuffix::None
192 }
193}
194
195macro_rules! lit_extra_traits {
196 ($ty:ident, $field:ident) => {
197 #[cfg(feature = "extra-traits")]
198 impl Eq for $ty {}
199
200 #[cfg(feature = "extra-traits")]
201 impl PartialEq for $ty {
202 fn eq(&self, other: &Self) -> bool {
203 self.$field.to_string() == other.$field.to_string()
204 }
205 }
206
207 #[cfg(feature = "extra-traits")]
208 impl Hash for $ty {
209 fn hash<H>(&self, state: &mut H)
210 where
211 H: Hasher,
212 {
213 self.$field.to_string().hash(state);
214 }
David Tolnay9c76bcb2017-12-26 23:14:59 -0500215 }
Alex Crichton62a0a592017-05-22 13:58:53 -0700216 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700217}
218
David Tolnay360efd22018-01-04 23:35:26 -0800219lit_extra_traits!(LitStr, token);
220lit_extra_traits!(LitByteStr, token);
221lit_extra_traits!(LitByte, token);
222lit_extra_traits!(LitChar, token);
223lit_extra_traits!(LitInt, token);
224lit_extra_traits!(LitFloat, token);
225lit_extra_traits!(LitBool, value);
226lit_extra_traits!(LitVerbatim, token);
227
228ast_enum! {
229 pub enum StrStyle #no_visit {
230 /// A regular string, like `"foo"`
231 Cooked,
232 /// A raw string, like `r##"foo"##`
233 ///
234 /// The unsigned integer is the number of `#` symbols used.
235 Raw(usize),
Alex Crichton62a0a592017-05-22 13:58:53 -0700236 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700237}
238
David Tolnay360efd22018-01-04 23:35:26 -0800239ast_enum! {
240 pub enum IntSuffix #no_visit {
241 I8,
242 I16,
243 I32,
244 I64,
245 I128,
246 Isize,
247 U8,
248 U16,
249 U32,
250 U64,
251 U128,
252 Usize,
253 None,
Pascal Hertleif36342c52016-10-19 10:31:42 +0200254 }
255}
256
David Tolnay360efd22018-01-04 23:35:26 -0800257ast_enum! {
258 pub enum FloatSuffix #no_visit {
259 F32,
260 F64,
261 None,
Alex Crichton2e0229c2017-05-23 09:34:50 -0700262 }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800263}
264
265#[cfg(feature = "parsing")]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700266pub mod parsing {
267 use super::*;
David Tolnayc5ab8c62017-12-26 16:43:39 -0500268 use synom::Synom;
269 use cursor::Cursor;
David Tolnay203557a2017-12-27 23:59:33 -0500270 use parse_error;
271 use synom::PResult;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700272
Alex Crichton954046c2017-05-30 21:49:42 -0700273 impl Synom for Lit {
Michael Layzell92639a52017-06-01 00:07:44 -0400274 fn parse(input: Cursor) -> PResult<Self> {
Michael Layzell589a8f42017-06-02 19:47:01 -0400275 match input.literal() {
David Tolnay360efd22018-01-04 23:35:26 -0800276 Some((span, lit, rest)) => Ok((Lit::new(lit, span), rest)),
David Tolnay73c98de2017-12-31 15:56:56 -0500277 _ => match input.term() {
David Tolnay360efd22018-01-04 23:35:26 -0800278 Some((span, term, rest)) => Ok((
279 Lit::Bool(LitBool {
280 value: if term.as_str() == "true" {
281 true
282 } else if term.as_str() == "false" {
283 false
284 } else {
285 return parse_error();
David Tolnay51382052017-12-27 13:46:21 -0500286 },
David Tolnay360efd22018-01-04 23:35:26 -0800287 span: span,
288 }),
289 rest,
290 )),
Michael Layzell589a8f42017-06-02 19:47:01 -0400291 _ => parse_error(),
David Tolnay51382052017-12-27 13:46:21 -0500292 },
Michael Layzell589a8f42017-06-02 19:47:01 -0400293 }
David Tolnayfa0edf22016-09-23 22:58:24 -0700294 }
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800295
296 fn description() -> Option<&'static str> {
297 Some("literal")
298 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700299 }
David Tolnay360efd22018-01-04 23:35:26 -0800300
301 impl_synom!(LitStr "string literal" switch!(
302 syn!(Lit),
303 Lit::Str(lit) => value!(lit)
304 |
305 _ => reject!()
306 ));
307
308 impl_synom!(LitByteStr "byte string literal" switch!(
309 syn!(Lit),
310 Lit::ByteStr(lit) => value!(lit)
311 |
312 _ => reject!()
313 ));
314
315 impl_synom!(LitByte "byte literal" switch!(
316 syn!(Lit),
317 Lit::Byte(lit) => value!(lit)
318 |
319 _ => reject!()
320 ));
321
322 impl_synom!(LitChar "character literal" switch!(
323 syn!(Lit),
324 Lit::Char(lit) => value!(lit)
325 |
326 _ => reject!()
327 ));
328
329 impl_synom!(LitInt "integer literal" switch!(
330 syn!(Lit),
331 Lit::Int(lit) => value!(lit)
332 |
333 _ => reject!()
334 ));
335
336 impl_synom!(LitFloat "floating point literal" switch!(
337 syn!(Lit),
338 Lit::Float(lit) => value!(lit)
339 |
340 _ => reject!()
341 ));
342
343 impl_synom!(LitBool "boolean literal" switch!(
344 syn!(Lit),
345 Lit::Bool(lit) => value!(lit)
346 |
347 _ => reject!()
348 ));
349
350 impl Lit {
351 pub fn new(token: Literal, span: Span) -> Self {
352 let value = token.to_string();
353
354 match value::byte(&value, 0) {
355 b'"' | b'r' => return Lit::Str(LitStr {
356 token: token,
357 span: span,
358 }),
359 b'b' => match value::byte(&value, 1) {
360 b'"' | b'r' => return Lit::ByteStr(LitByteStr {
361 token: token,
362 span: span,
363 }),
364 b'\'' => return Lit::Byte(LitByte {
365 token: token,
366 span: span,
367 }),
368 _ => {}
369 }
370 b'\'' => return Lit::Char(LitChar {
371 token: token,
372 span: span,
373 }),
374 b'0'...b'9' => if number_is_int(&value) {
375 return Lit::Int(LitInt {
376 token: token,
377 span: span,
378 });
379 } else if number_is_float(&value) {
380 return Lit::Float(LitFloat {
381 token: token,
382 span: span,
383 });
384 } else {
385 // number overflow
386 return Lit::Verbatim(LitVerbatim {
387 token: token,
388 span: span,
389 });
390 }
391 _ => if value == "true" || value == "false" {
392 return Lit::Bool(LitBool {
393 value: value == "true",
394 span: span,
395 });
396 }
397 }
398
399 panic!("Unrecognized literal: {}", value);
400 }
401 }
402
403 fn number_is_int(value: &str) -> bool {
404 if number_is_float(value) {
405 false
406 } else {
407 value::parse_lit_int(value).is_some()
408 }
409 }
410
411 fn number_is_float(value: &str) -> bool {
412 if value.contains('.') {
413 true
414 } else if value.starts_with("0x") || value.ends_with("size") {
415 false
416 } else {
417 value.contains('e') || value.contains('E')
418 }
419 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700420}
421
422#[cfg(feature = "printing")]
423mod printing {
424 use super::*;
David Tolnay51382052017-12-27 13:46:21 -0500425 use quote::{ToTokens, Tokens};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700426
David Tolnay360efd22018-01-04 23:35:26 -0800427 impl ToTokens for LitStr {
David Tolnayf4bbbd92016-09-23 14:41:55 -0700428 fn to_tokens(&self, tokens: &mut Tokens) {
David Tolnay360efd22018-01-04 23:35:26 -0800429 tokens.append(TokenTree {
430 span: self.span,
431 kind: TokenNode::Literal(self.token.clone()),
432 });
433 }
434 }
435
436 impl ToTokens for LitByteStr {
437 fn to_tokens(&self, tokens: &mut Tokens) {
438 tokens.append(TokenTree {
439 span: self.span,
440 kind: TokenNode::Literal(self.token.clone()),
441 });
442 }
443 }
444
445 impl ToTokens for LitByte {
446 fn to_tokens(&self, tokens: &mut Tokens) {
447 tokens.append(TokenTree {
448 span: self.span,
449 kind: TokenNode::Literal(self.token.clone()),
450 });
451 }
452 }
453
454 impl ToTokens for LitChar {
455 fn to_tokens(&self, tokens: &mut Tokens) {
456 tokens.append(TokenTree {
457 span: self.span,
458 kind: TokenNode::Literal(self.token.clone()),
459 });
460 }
461 }
462
463 impl ToTokens for LitInt {
464 fn to_tokens(&self, tokens: &mut Tokens) {
465 tokens.append(TokenTree {
466 span: self.span,
467 kind: TokenNode::Literal(self.token.clone()),
468 });
469 }
470 }
471
472 impl ToTokens for LitFloat {
473 fn to_tokens(&self, tokens: &mut Tokens) {
474 tokens.append(TokenTree {
475 span: self.span,
476 kind: TokenNode::Literal(self.token.clone()),
477 });
478 }
479 }
480
481 impl ToTokens for LitBool {
482 fn to_tokens(&self, tokens: &mut Tokens) {
483 tokens.append(TokenTree {
484 span: self.span,
485 kind: TokenNode::Term(Term::intern(if self.value {
486 "true"
487 } else {
488 "false"
489 })),
490 });
491 }
492 }
493
494 impl ToTokens for LitVerbatim {
495 fn to_tokens(&self, tokens: &mut Tokens) {
496 tokens.append(TokenTree {
497 span: self.span,
498 kind: TokenNode::Literal(self.token.clone()),
499 });
500 }
501 }
502}
503
504mod value {
505 use super::*;
506 use std::char;
507 use std::ops::{Index, RangeFrom};
508 use proc_macro2::TokenStream;
509
510 /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
511 /// past the end of the input buffer.
512 pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
513 let s = s.as_ref();
514 if idx < s.len() {
515 s[idx]
516 } else {
517 0
518 }
519 }
520
521 fn next_chr(s: &str) -> char {
522 s.chars().next().unwrap_or('\0')
523 }
524
525 pub fn parse_lit_str(s: &str) -> String {
526 match byte(s, 0) {
527 b'"' => parse_lit_str_cooked(s),
528 b'r' => parse_lit_str_raw(s),
529 _ => unreachable!(),
530 }
531 }
532
533 fn parse_lit_str_cooked(mut s: &str) -> String {
534 assert_eq!(byte(s, 0), b'"');
535 s = &s[1..];
536
537 let mut out = String::new();
538 'outer: loop {
539 let ch = match byte(s, 0) {
540 b'"' => break,
541 b'\\' => {
542 let b = byte(s, 1);
543 s = &s[2..];
544 match b {
545 b'x' => {
546 let (byte, rest) = backslash_x(s);
547 s = rest;
548 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
549 char::from_u32(byte as u32).unwrap()
550 }
551 b'u' => {
552 let (chr, rest) = backslash_u(&s);
553 s = rest;
554 chr
555 }
556 b'n' => '\n',
557 b'r' => '\r',
558 b't' => '\t',
559 b'\\' => '\\',
560 b'0' => '\0',
561 b'\'' => '\'',
562 b'"' => '"',
563 b'\r' | b'\n' => {
564 loop {
565 let ch = next_chr(s);
566 if ch.is_whitespace() {
567 s = &s[ch.len_utf8()..];
568 } else {
569 continue 'outer;
570 }
571 }
572 }
573 b => {
574 panic!("unexpected byte {:?} after \\ character in byte literal", b)
575 }
576 }
577 }
578 b'\r' => {
579 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
580 s = &s[2..];
581 '\n'
582 }
583 _ => {
584 let ch = next_chr(s);
585 s = &s[ch.len_utf8()..];
586 ch
587 }
588 };
589 out.push(ch);
590 }
591
592 assert_eq!(s, "\"");
593 out
594 }
595
596 fn parse_lit_str_raw(mut s: &str) -> String {
597 assert_eq!(byte(s, 0), b'r');
598 s = &s[1..];
599
600 let mut pounds = 0;
601 while byte(s, pounds) == b'#' {
602 pounds += 1;
603 }
604 assert_eq!(byte(s, pounds), b'"');
605 assert_eq!(byte(s, s.len() - pounds - 1), b'"');
606 for end in s[s.len() - pounds..].bytes() {
607 assert_eq!(end, b'#');
608 }
609
610 s[pounds + 1..s.len() - pounds - 1].to_owned()
611 }
612
613 pub fn parse_lit_byte_str(s: &str) -> Vec<u8> {
614 assert_eq!(byte(s, 0), b'b');
615 match byte(s, 1) {
616 b'"' => parse_lit_byte_str_cooked(s),
617 b'r' => parse_lit_byte_str_raw(s),
618 _ => unreachable!(),
619 }
620 }
621
622 fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> {
623 assert_eq!(byte(s, 0), b'b');
624 assert_eq!(byte(s, 1), b'"');
625 s = &s[2..];
626
627 // We're going to want to have slices which don't respect codepoint boundaries.
628 let mut s = s.as_bytes();
629
630 let mut out = Vec::new();
631 'outer: loop {
632 let byte = match byte(s, 0) {
633 b'"' => break,
634 b'\\' => {
635 let b = byte(s, 1);
636 s = &s[2..];
637 match b {
638 b'x' => {
639 let (b, rest) = backslash_x(s);
640 s = rest;
641 b
642 }
643 b'n' => b'\n',
644 b'r' => b'\r',
645 b't' => b'\t',
646 b'\\' => b'\\',
647 b'0' => b'\0',
648 b'\'' => b'\'',
649 b'"' => b'"',
650 b'\r' | b'\n' => {
651 loop {
652 let byte = byte(s, 0);
653 let ch = char::from_u32(byte as u32).unwrap();
654 if ch.is_whitespace() {
655 s = &s[1..];
656 } else {
657 continue 'outer;
658 }
659 }
660 }
661 b => {
662 panic!("unexpected byte {:?} after \\ character in byte literal", b)
663 }
664 }
665 }
666 b'\r' => {
667 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
668 s = &s[2..];
669 b'\n'
670 }
671 b => {
672 s = &s[1..];
673 b
674 }
675 };
676 out.push(byte);
677 }
678
679 assert_eq!(s, b"\"");
680 out
681 }
682
683 fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> {
684 assert_eq!(byte(s, 0), b'b');
685 parse_lit_str_raw(&s[1..]).into_bytes()
686 }
687
688 pub fn parse_lit_byte(s: &str) -> u8 {
689 assert_eq!(byte(s, 0), b'b');
690 assert_eq!(byte(s, 1), b'\'');
691
692 // We're going to want to have slices which don't respect codepoint boundaries.
693 let mut s = s[2..].as_bytes();
694
695 let b = match byte(s, 0) {
696 b'\\' => {
697 let b = byte(s, 1);
698 s = &s[2..];
699 match b {
700 b'x' => {
701 let (b, rest) = backslash_x(s);
702 s = rest;
703 b
704 }
705 b'n' => b'\n',
706 b'r' => b'\r',
707 b't' => b'\t',
708 b'\\' => b'\\',
709 b'0' => b'\0',
710 b'\'' => b'\'',
711 b'"' => b'"',
712 b => {
713 panic!("unexpected byte {:?} after \\ character in byte literal", b)
714 }
715 }
716 }
717 b => {
718 s = &s[1..];
719 b
720 }
721 };
722
723 assert_eq!(byte(s, 0), b'\'');
724 b
725 }
726
727 pub fn parse_lit_char(mut s: &str) -> char {
728 assert_eq!(byte(s, 0), b'\'');
729 s = &s[1..];
730
731 let ch = match byte(s, 0) {
732 b'\\' => {
733 let b = byte(s, 1);
734 s = &s[2..];
735 match b {
736 b'x' => {
737 let (byte, rest) = backslash_x(s);
738 s = rest;
739 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
740 char::from_u32(byte as u32).unwrap()
741 }
742 b'u' => {
743 let (chr, rest) = backslash_u(s);
744 s = rest;
745 chr
746 }
747 b'n' => '\n',
748 b'r' => '\r',
749 b't' => '\t',
750 b'\\' => '\\',
751 b'0' => '\0',
752 b'\'' => '\'',
753 b'"' => '"',
754 b => {
755 panic!("unexpected byte {:?} after \\ character in byte literal", b)
756 }
757 }
758 }
759 _ => {
760 let ch = next_chr(s);
761 s = &s[ch.len_utf8()..];
762 ch
763 }
764 };
765 assert_eq!(s, "\'", "Expected end of char literal");
766 ch
767 }
768
769 fn backslash_x<S>(s: &S) -> (u8, &S)
770 where S: Index<RangeFrom<usize>, Output=S> + AsRef<[u8]> + ?Sized
771 {
772 let mut ch = 0;
773 let b0 = byte(s, 0);
774 let b1 = byte(s, 1);
775 ch += 0x10 * match b0 {
776 b'0'...b'9' => b0 - b'0',
777 b'a'...b'f' => 10 + (b0 - b'a'),
778 b'A'...b'F' => 10 + (b0 - b'A'),
779 _ => panic!("unexpected non-hex character after \\x"),
780 };
781 ch += 0x1 * match b1 {
782 b'0'...b'9' => b1 - b'0',
783 b'a'...b'f' => 10 + (b1 - b'a'),
784 b'A'...b'F' => 10 + (b1 - b'A'),
785 _ => panic!("unexpected non-hex character after \\x"),
786 };
787 (ch, &s[2..])
788 }
789
790 fn backslash_u(mut s: &str) -> (char, &str) {
791 if byte(s, 0) != b'{' {
792 panic!("expected {{ after \\u");
793 }
794 s = &s[1..];
795
796 let mut ch = 0;
797 for _ in 0..6 {
798 let b = byte(s, 0);
799 match b {
800 b'0'...b'9' => {
801 ch *= 0x10;
802 ch += (b - b'0') as u32;
803 s = &s[1..];
804 }
805 b'a'...b'f' => {
806 ch *= 0x10;
807 ch += (10 + b - b'a') as u32;
808 s = &s[1..];
809 }
810 b'A'...b'F' => {
811 ch *= 0x10;
812 ch += (10 + b - b'A') as u32;
813 s = &s[1..];
814 }
815 b'}' => break,
816 _ => panic!("unexpected non-hex character after \\u"),
817 }
818 }
819 assert!(byte(s, 0) == b'}');
820 s = &s[1..];
821
822 if let Some(ch) = char::from_u32(ch) {
823 (ch, s)
824 } else {
825 panic!("character code {:x} is not a valid unicode character", ch);
826 }
827 }
828
829 pub fn parse_lit_int(mut s: &str) -> Option<u64> {
830 let base = match (byte(s, 0), byte(s, 1)) {
831 (b'0', b'x') => {
832 s = &s[2..];
833 16
834 }
835 (b'0', b'o') => {
836 s = &s[2..];
837 8
838 }
839 (b'0', b'b') => {
840 s = &s[2..];
841 2
842 }
843 (b'0'...b'9', _) => 10,
844 _ => unreachable!(),
845 };
846
847 let mut value = 0u64;
848 loop {
849 let b = byte(s, 0);
850 let digit = match b {
851 b'0'...b'9' => (b - b'0') as u64,
852 b'a'...b'f' if base > 10 => 10 + (b - b'a') as u64,
853 b'A'...b'F' if base > 10 => 10 + (b - b'A') as u64,
854 b'_' => {
855 s = &s[1..];
856 continue;
857 }
858 // NOTE: Looking at a floating point literal, we don't want to
859 // consider these integers.
860 b'.' if base == 10 => return None,
861 b'e' | b'E' if base == 10 => return None,
862 _ => break,
863 };
864
865 if digit >= base {
866 panic!("Unexpected digit {:x} out of base range", digit);
867 }
868
869 value = match value.checked_mul(base) {
870 Some(value) => value,
871 None => return None,
872 };
873 value = match value.checked_add(digit) {
874 Some(value) => value,
875 None => return None,
876 };
877 s = &s[1..];
878 }
879
880 Some(value)
881 }
882
883 pub fn parse_lit_float(input: &str) -> f64 {
884 // Rust's floating point literals are very similar to the ones parsed by
885 // the standard library, except that rust's literals can contain
886 // ignorable underscores. Let's remove those underscores.
887 let mut bytes = input.to_owned().into_bytes();
888 let mut write = 0;
889 for read in 0..bytes.len() {
890 if bytes[read] == b'_' {
891 continue; // Don't increase write
892 } else if write != read {
893 let x = bytes[read];
894 bytes[write] = x;
895 }
896 write += 1;
897 }
898 bytes.truncate(write);
899 let input = String::from_utf8(bytes).unwrap();
900 let end = input.find('f').unwrap_or(input.len());
901 input[..end].parse().unwrap()
902 }
903
904 pub fn to_literal(s: &str) -> Literal {
905 let stream = s.parse::<TokenStream>().unwrap();
906 match stream.into_iter().next().unwrap().kind {
907 TokenNode::Literal(l) => l,
908 _ => unreachable!(),
David Tolnayf17fd2f2016-10-07 23:38:08 -0700909 }
910 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700911}