• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::fmt;
2 
3 use crate::{
4     Buffer, ParseError,
5     err::{perr, ParseErrorKind::*},
6     escape::unescape,
7     parse::{first_byte_or_empty, check_suffix},
8 };
9 
10 
11 /// A character literal, e.g. `'g'` or `'��'`.
12 ///
13 /// See [the reference][ref] for more information.
14 ///
15 /// [ref]: https://doc.rust-lang.org/reference/tokens.html#character-literals
16 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
17 pub struct CharLit<B: Buffer> {
18     raw: B,
19     /// Start index of the suffix or `raw.len()` if there is no suffix.
20     start_suffix: usize,
21     value: char,
22 }
23 
24 impl<B: Buffer> CharLit<B> {
25     /// Parses the input as a character literal. Returns an error if the input
26     /// is invalid or represents a different kind of literal.
parse(input: B) -> Result<Self, ParseError>27     pub fn parse(input: B) -> Result<Self, ParseError> {
28         match first_byte_or_empty(&input)? {
29             b'\'' => {
30                 let (value, start_suffix) = parse_impl(&input)?;
31                 Ok(Self { raw: input, value, start_suffix })
32             },
33             _ => Err(perr(0, DoesNotStartWithQuote)),
34         }
35     }
36 
37     /// Returns the character value that this literal represents.
value(&self) -> char38     pub fn value(&self) -> char {
39         self.value
40     }
41 
42     /// The optional suffix. Returns `""` if the suffix is empty/does not exist.
suffix(&self) -> &str43     pub fn suffix(&self) -> &str {
44         &(*self.raw)[self.start_suffix..]
45     }
46 
47     /// Returns the raw input that was passed to `parse`.
raw_input(&self) -> &str48     pub fn raw_input(&self) -> &str {
49         &self.raw
50     }
51 
52     /// Returns the raw input that was passed to `parse`, potentially owned.
into_raw_input(self) -> B53     pub fn into_raw_input(self) -> B {
54         self.raw
55     }
56 
57 }
58 
59 impl CharLit<&str> {
60     /// Makes a copy of the underlying buffer and returns the owned version of
61     /// `Self`.
to_owned(&self) -> CharLit<String>62     pub fn to_owned(&self) -> CharLit<String> {
63         CharLit {
64             raw: self.raw.to_owned(),
65             start_suffix: self.start_suffix,
66             value: self.value,
67         }
68     }
69 }
70 
71 impl<B: Buffer> fmt::Display for CharLit<B> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result72     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73         f.pad(&self.raw)
74     }
75 }
76 
77 /// Precondition: first character in input must be `'`.
78 #[inline(never)]
parse_impl(input: &str) -> Result<(char, usize), ParseError>79 pub(crate) fn parse_impl(input: &str) -> Result<(char, usize), ParseError> {
80     let first = input.chars().nth(1).ok_or(perr(None, UnterminatedCharLiteral))?;
81     let (c, len) = match first {
82         '\'' if input.chars().nth(2) == Some('\'') => return Err(perr(1, UnescapedSingleQuote)),
83         '\'' => return Err(perr(None, EmptyCharLiteral)),
84         '\n' | '\t' | '\r'
85             => return Err(perr(1, UnescapedSpecialWhitespace)),
86 
87         '\\' => unescape::<char>(&input[1..], 1)?,
88         other => (other, other.len_utf8()),
89     };
90 
91     match input[1 + len..].find('\'') {
92         Some(0) => {}
93         Some(_) => return Err(perr(None, OverlongCharLiteral)),
94         None => return Err(perr(None, UnterminatedCharLiteral)),
95     }
96 
97     let start_suffix = 1 + len + 1;
98     let suffix = &input[start_suffix..];
99     check_suffix(suffix).map_err(|kind| perr(start_suffix, kind))?;
100 
101     Ok((c, start_suffix))
102 }
103 
104 #[cfg(test)]
105 mod tests;
106