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