|
2 | 2 |
|
3 | 3 | use crate::ast::{self, LitKind, MetaItemLit, StrStyle};
|
4 | 4 | use crate::token::{self, Token};
|
5 |
| -use rustc_lexer::unescape::{byte_from_char, unescape_byte, unescape_char, unescape_literal, Mode}; |
| 5 | +use rustc_lexer::unescape::{ |
| 6 | + byte_from_char, unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, |
| 7 | + Mode, |
| 8 | +}; |
6 | 9 | use rustc_span::symbol::{kw, sym, Symbol};
|
7 | 10 | use rustc_span::Span;
|
| 11 | +use std::ops::Range; |
8 | 12 | use std::{ascii, fmt, str};
|
9 | 13 |
|
10 | 14 | // Escapes a string, represented as a symbol. Reuses the original symbol,
|
@@ -35,6 +39,7 @@ pub enum LitError {
|
35 | 39 | InvalidFloatSuffix,
|
36 | 40 | NonDecimalFloat(u32),
|
37 | 41 | IntTooLarge(u32),
|
| 42 | + NulInCStr(Range<usize>), |
38 | 43 | }
|
39 | 44 |
|
40 | 45 | impl LitKind {
|
@@ -158,6 +163,52 @@ impl LitKind {
|
158 | 163 |
|
159 | 164 | LitKind::ByteStr(bytes.into(), StrStyle::Raw(n))
|
160 | 165 | }
|
| 166 | + token::CStr => { |
| 167 | + let s = symbol.as_str(); |
| 168 | + let mut buf = Vec::with_capacity(s.len()); |
| 169 | + let mut error = Ok(()); |
| 170 | + unescape_c_string(s, Mode::CStr, &mut |span, c| match c { |
| 171 | + Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => { |
| 172 | + error = Err(LitError::NulInCStr(span)); |
| 173 | + } |
| 174 | + Ok(CStrUnit::Byte(b)) => buf.push(b), |
| 175 | + Ok(CStrUnit::Char(c)) if c.len_utf8() == 1 => buf.push(c as u8), |
| 176 | + Ok(CStrUnit::Char(c)) => { |
| 177 | + buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) |
| 178 | + } |
| 179 | + Err(err) => { |
| 180 | + if err.is_fatal() { |
| 181 | + error = Err(LitError::LexerError); |
| 182 | + } |
| 183 | + } |
| 184 | + }); |
| 185 | + error?; |
| 186 | + buf.push(0); |
| 187 | + LitKind::CStr(buf.into(), StrStyle::Cooked) |
| 188 | + } |
| 189 | + token::CStrRaw(n) => { |
| 190 | + let s = symbol.as_str(); |
| 191 | + let mut buf = Vec::with_capacity(s.len()); |
| 192 | + let mut error = Ok(()); |
| 193 | + unescape_c_string(s, Mode::RawCStr, &mut |span, c| match c { |
| 194 | + Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => { |
| 195 | + error = Err(LitError::NulInCStr(span)); |
| 196 | + } |
| 197 | + Ok(CStrUnit::Byte(b)) => buf.push(b), |
| 198 | + Ok(CStrUnit::Char(c)) if c.len_utf8() == 1 => buf.push(c as u8), |
| 199 | + Ok(CStrUnit::Char(c)) => { |
| 200 | + buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) |
| 201 | + } |
| 202 | + Err(err) => { |
| 203 | + if err.is_fatal() { |
| 204 | + error = Err(LitError::LexerError); |
| 205 | + } |
| 206 | + } |
| 207 | + }); |
| 208 | + error?; |
| 209 | + buf.push(0); |
| 210 | + LitKind::CStr(buf.into(), StrStyle::Raw(n)) |
| 211 | + } |
161 | 212 | token::Err => LitKind::Err,
|
162 | 213 | })
|
163 | 214 | }
|
@@ -191,6 +242,14 @@ impl fmt::Display for LitKind {
|
191 | 242 | string = symbol
|
192 | 243 | )?;
|
193 | 244 | }
|
| 245 | + LitKind::CStr(ref bytes, StrStyle::Cooked) => { |
| 246 | + write!(f, "c\"{}\"", escape_byte_str_symbol(bytes))? |
| 247 | + } |
| 248 | + LitKind::CStr(ref bytes, StrStyle::Raw(n)) => { |
| 249 | + // This can only be valid UTF-8. |
| 250 | + let symbol = str::from_utf8(bytes).unwrap(); |
| 251 | + write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize),)?; |
| 252 | + } |
194 | 253 | LitKind::Int(n, ty) => {
|
195 | 254 | write!(f, "{n}")?;
|
196 | 255 | match ty {
|
@@ -237,6 +296,8 @@ impl MetaItemLit {
|
237 | 296 | LitKind::Str(_, ast::StrStyle::Raw(n)) => token::StrRaw(n),
|
238 | 297 | LitKind::ByteStr(_, ast::StrStyle::Cooked) => token::ByteStr,
|
239 | 298 | LitKind::ByteStr(_, ast::StrStyle::Raw(n)) => token::ByteStrRaw(n),
|
| 299 | + LitKind::CStr(_, ast::StrStyle::Cooked) => token::CStr, |
| 300 | + LitKind::CStr(_, ast::StrStyle::Raw(n)) => token::CStrRaw(n), |
240 | 301 | LitKind::Byte(_) => token::Byte,
|
241 | 302 | LitKind::Char(_) => token::Char,
|
242 | 303 | LitKind::Int(..) => token::Integer,
|
|
0 commit comments