• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::{
2     BoolLit,
3     Buffer,
4     ByteLit,
5     ByteStringLit,
6     CharLit,
7     ParseError,
8     FloatLit,
9     IntegerLit,
10     Literal,
11     StringLit,
12     err::{perr, ParseErrorKind::*},
13 };
14 
15 
16 impl<B: Buffer> Literal<B> {
17     /// Parses the given input as a Rust literal.
parse(input: B) -> Result<Self, ParseError>18     pub fn parse(input: B) -> Result<Self, ParseError> {
19         let (first, rest) = input.as_bytes().split_first().ok_or(perr(None, Empty))?;
20         let second = input.as_bytes().get(1).copied();
21 
22         match first {
23             b'f' if &*input == "false" => Ok(Self::Bool(BoolLit::False)),
24             b't' if &*input == "true" => Ok(Self::Bool(BoolLit::True)),
25 
26             // A number literal (integer or float).
27             b'0'..=b'9' => {
28                 // To figure out whether this is a float or integer, we do some
29                 // quick inspection here. Yes, this is technically duplicate
30                 // work with what is happening in the integer/float parse
31                 // methods, but it makes the code way easier for now and won't
32                 // be a huge performance loss.
33                 let end = 1 + end_dec_digits(rest);
34                 match input.as_bytes().get(end) {
35                     // Potential chars in integer literals: b, o, x for base; u
36                     // and i for type suffix.
37                     None | Some(b'b') | Some(b'o') | Some(b'x') | Some(b'u') | Some(b'i')
38                         => IntegerLit::parse(input).map(Literal::Integer),
39 
40                     // Potential chars for float literals: `.` as fractional
41                     // period, e and E as exponent start and f as type suffix.
42                     Some(b'.') | Some(b'e') | Some(b'E') | Some(b'f')
43                         => FloatLit::parse(input).map(Literal::Float),
44 
45                     _ => Err(perr(end, UnexpectedChar)),
46                 }
47             },
48 
49             b'\'' => CharLit::parse(input).map(Literal::Char),
50             b'"' | b'r' => StringLit::parse_impl(input).map(Literal::String),
51 
52             b'b' if second == Some(b'\'') => ByteLit::parse(input).map(Literal::Byte),
53             b'b' if second == Some(b'r') || second == Some(b'"')
54                 => ByteStringLit::parse_impl(input).map(Literal::ByteString),
55 
56             _ => Err(perr(None, InvalidLiteral)),
57         }
58     }
59 }
60 
61 
first_byte_or_empty(s: &str) -> Result<u8, ParseError>62 pub(crate) fn first_byte_or_empty(s: &str) -> Result<u8, ParseError> {
63     s.as_bytes().get(0).copied().ok_or(perr(None, Empty))
64 }
65 
66 /// Returns the index of the first non-underscore, non-decimal digit in `input`,
67 /// or the `input.len()` if all characters are decimal digits.
end_dec_digits(input: &[u8]) -> usize68 pub(crate) fn end_dec_digits(input: &[u8]) -> usize {
69     input.iter()
70         .position(|b| !matches!(b, b'_' | b'0'..=b'9'))
71         .unwrap_or(input.len())
72 }
73 
hex_digit_value(digit: u8) -> Option<u8>74 pub(crate) fn hex_digit_value(digit: u8) -> Option<u8> {
75     match digit {
76         b'0'..=b'9' => Some(digit - b'0'),
77         b'a'..=b'f' => Some(digit - b'a' + 10),
78         b'A'..=b'F' => Some(digit - b'A' + 10),
79         _ => None,
80     }
81 }
82