Stringify literals create client-side properly

This commit is contained in:
Amos Wenger 2022-07-21 18:44:41 +02:00
parent 36d825fd5d
commit 9cf99a9c71
2 changed files with 51 additions and 11 deletions

View file

@ -132,17 +132,11 @@ impl server::TokenStream for RustAnalyzer {
} }
bridge::TokenTree::Literal(literal) => { bridge::TokenTree::Literal(literal) => {
// FIXME: remove unnecessary clones here let literal = LiteralFormatter(literal);
let symbol = ThreadLocalSymbolInterner::get_cloned(&literal.symbol); let text = literal
.with_stringify_parts(|parts| tt::SmolStr::from_iter(parts.iter().copied()));
let text: tt::SmolStr = if let Some(suffix) = literal.suffix { let literal = tt::Literal { text, id: literal.0.span };
let suffix = ThreadLocalSymbolInterner::get_cloned(&suffix);
format!("{symbol}{suffix}").into()
} else {
symbol
};
let literal = tt::Literal { text, id: literal.span };
let leaf = tt::Leaf::from(literal); let leaf = tt::Leaf::from(literal);
let tree = TokenTree::from(leaf); let tree = TokenTree::from(leaf);
Self::TokenStream::from_iter(vec![tree]) Self::TokenStream::from_iter(vec![tree])
@ -416,6 +410,53 @@ impl server::Server for RustAnalyzer {
} }
} }
struct LiteralFormatter(bridge::Literal<tt::TokenId, Symbol>);
impl LiteralFormatter {
/// Invokes the callback with a `&[&str]` consisting of each part of the
/// literal's representation. This is done to allow the `ToString` and
/// `Display` implementations to borrow references to symbol values, and
/// both be optimized to reduce overhead.
fn with_stringify_parts<R>(&self, f: impl FnOnce(&[&str]) -> R) -> R {
/// Returns a string containing exactly `num` '#' characters.
/// Uses a 256-character source string literal which is always safe to
/// index with a `u8` index.
fn get_hashes_str(num: u8) -> &'static str {
const HASHES: &str = "\
################################################################\
################################################################\
################################################################\
################################################################\
";
const _: () = assert!(HASHES.len() == 256);
&HASHES[..num as usize]
}
self.with_symbol_and_suffix(|symbol, suffix| match self.0.kind {
bridge::LitKind::Byte => f(&["b'", symbol, "'", suffix]),
bridge::LitKind::Char => f(&["'", symbol, "'", suffix]),
bridge::LitKind::Str => f(&["\"", symbol, "\"", suffix]),
bridge::LitKind::StrRaw(n) => {
let hashes = get_hashes_str(n);
f(&["r", hashes, "\"", symbol, "\"", hashes, suffix])
}
bridge::LitKind::ByteStr => f(&["b\"", symbol, "\"", suffix]),
bridge::LitKind::ByteStrRaw(n) => {
let hashes = get_hashes_str(n);
f(&["br", hashes, "\"", symbol, "\"", hashes, suffix])
}
_ => f(&[symbol, suffix]),
})
}
fn with_symbol_and_suffix<R>(&self, f: impl FnOnce(&str, &str) -> R) -> R {
ThreadLocalSymbolInterner::with(&self.0.symbol, |symbol| match self.0.suffix.as_ref() {
Some(suffix) => ThreadLocalSymbolInterner::with(suffix, |suffix| f(symbol, suffix)),
None => f(symbol, ""),
})
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -77,7 +77,6 @@ fn test_fn_like_mk_literals() {
LITERAL b"byte_string" 4294967295 LITERAL b"byte_string" 4294967295
LITERAL 'c' 4294967295 LITERAL 'c' 4294967295
LITERAL "string" 4294967295 LITERAL "string" 4294967295
LITERAL "maybe \"raw\"?" 4294967295
LITERAL 3.14f64 4294967295 LITERAL 3.14f64 4294967295
LITERAL 3.14 4294967295 LITERAL 3.14 4294967295
LITERAL 123i64 4294967295 LITERAL 123i64 4294967295