mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 16:54:01 +00:00
proc_macro: stop using a remote object handle for Literal
This builds on the symbol infrastructure built for `Ident` to replicate the `LitKind` and `Lit` structures in rustc within the `proc_macro` client, allowing literals to be fully created and interacted with from the client thread. Only parsing and subspan operations still require sync RPC.
This commit is contained in:
parent
491fccfbe3
commit
b34c79f8f1
@ -14,9 +14,10 @@ use rustc_span::def_id::CrateNum;
|
||||
use rustc_span::symbol::{self, sym, Symbol};
|
||||
use rustc_span::{BytePos, FileName, Pos, SourceFile, Span};
|
||||
|
||||
use pm::bridge::{server, DelimSpan, ExpnGlobals, Group, Ident, Punct, TokenTree};
|
||||
use pm::bridge::{
|
||||
server, DelimSpan, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree,
|
||||
};
|
||||
use pm::{Delimiter, Level, LineColumn};
|
||||
use std::ascii;
|
||||
use std::ops::Bound;
|
||||
|
||||
trait FromInternal<T> {
|
||||
@ -49,9 +50,40 @@ impl ToInternal<token::Delimiter> for Delimiter {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)>
|
||||
for Vec<TokenTree<TokenStream, Span, Symbol, Literal>>
|
||||
{
|
||||
impl FromInternal<token::LitKind> for LitKind {
|
||||
fn from_internal(kind: token::LitKind) -> Self {
|
||||
match kind {
|
||||
token::Byte => LitKind::Byte,
|
||||
token::Char => LitKind::Char,
|
||||
token::Integer => LitKind::Integer,
|
||||
token::Float => LitKind::Float,
|
||||
token::Str => LitKind::Str,
|
||||
token::StrRaw(n) => LitKind::StrRaw(n),
|
||||
token::ByteStr => LitKind::ByteStr,
|
||||
token::ByteStrRaw(n) => LitKind::ByteStrRaw(n),
|
||||
token::Err => LitKind::Err,
|
||||
token::Bool => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToInternal<token::LitKind> for LitKind {
|
||||
fn to_internal(self) -> token::LitKind {
|
||||
match self {
|
||||
LitKind::Byte => token::Byte,
|
||||
LitKind::Char => token::Char,
|
||||
LitKind::Integer => token::Integer,
|
||||
LitKind::Float => token::Float,
|
||||
LitKind::Str => token::Str,
|
||||
LitKind::StrRaw(n) => token::StrRaw(n),
|
||||
LitKind::ByteStr => token::ByteStr,
|
||||
LitKind::ByteStrRaw(n) => token::ByteStrRaw(n),
|
||||
LitKind::Err => token::Err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStream, Span, Symbol>> {
|
||||
fn from_internal((stream, rustc): (TokenStream, &mut Rustc<'_, '_>)) -> Self {
|
||||
use rustc_ast::token::*;
|
||||
|
||||
@ -143,7 +175,14 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)>
|
||||
TokenTree::Ident(Ident { sym: ident.name, is_raw: false, span }),
|
||||
]);
|
||||
}
|
||||
Literal(lit) => trees.push(TokenTree::Literal(self::Literal { lit, span })),
|
||||
Literal(token::Lit { kind, symbol, suffix }) => {
|
||||
trees.push(TokenTree::Literal(self::Literal {
|
||||
kind: FromInternal::from_internal(kind),
|
||||
symbol,
|
||||
suffix,
|
||||
span,
|
||||
}));
|
||||
}
|
||||
DocComment(_, attr_style, data) => {
|
||||
let mut escaped = String::new();
|
||||
for ch in data.as_str().chars() {
|
||||
@ -199,9 +238,7 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)>
|
||||
}
|
||||
}
|
||||
|
||||
impl ToInternal<TokenStream>
|
||||
for (TokenTree<TokenStream, Span, Symbol, Literal>, &mut Rustc<'_, '_>)
|
||||
{
|
||||
impl ToInternal<TokenStream> for (TokenTree<TokenStream, Span, Symbol>, &mut Rustc<'_, '_>) {
|
||||
fn to_internal(self) -> TokenStream {
|
||||
use rustc_ast::token::*;
|
||||
|
||||
@ -221,7 +258,9 @@ impl ToInternal<TokenStream>
|
||||
return tokenstream::TokenTree::token(Ident(sym, is_raw), span).into();
|
||||
}
|
||||
TokenTree::Literal(self::Literal {
|
||||
lit: token::Lit { kind: token::Integer, symbol, suffix },
|
||||
kind: self::LitKind::Integer,
|
||||
symbol,
|
||||
suffix,
|
||||
span,
|
||||
}) if symbol.as_str().starts_with('-') => {
|
||||
let minus = BinOp(BinOpToken::Minus);
|
||||
@ -232,7 +271,9 @@ impl ToInternal<TokenStream>
|
||||
return [a, b].into_iter().collect();
|
||||
}
|
||||
TokenTree::Literal(self::Literal {
|
||||
lit: token::Lit { kind: token::Float, symbol, suffix },
|
||||
kind: self::LitKind::Float,
|
||||
symbol,
|
||||
suffix,
|
||||
span,
|
||||
}) if symbol.as_str().starts_with('-') => {
|
||||
let minus = BinOp(BinOpToken::Minus);
|
||||
@ -242,8 +283,12 @@ impl ToInternal<TokenStream>
|
||||
let b = tokenstream::TokenTree::token(float, span);
|
||||
return [a, b].into_iter().collect();
|
||||
}
|
||||
TokenTree::Literal(self::Literal { lit, span }) => {
|
||||
return tokenstream::TokenTree::token(Literal(lit), span).into();
|
||||
TokenTree::Literal(self::Literal { kind, symbol, suffix, span }) => {
|
||||
return tokenstream::TokenTree::token(
|
||||
TokenKind::lit(kind.to_internal(), symbol, suffix),
|
||||
span,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
};
|
||||
|
||||
@ -292,13 +337,6 @@ impl ToInternal<rustc_errors::Level> for Level {
|
||||
|
||||
pub struct FreeFunctions;
|
||||
|
||||
// FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Literal {
|
||||
lit: token::Lit,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
pub(crate) struct Rustc<'a, 'b> {
|
||||
ecx: &'a mut ExtCtxt<'b>,
|
||||
def_site: Span,
|
||||
@ -324,16 +362,11 @@ impl<'a, 'b> Rustc<'a, 'b> {
|
||||
fn sess(&self) -> &ParseSess {
|
||||
self.ecx.parse_sess()
|
||||
}
|
||||
|
||||
fn lit(&mut self, kind: token::LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Literal {
|
||||
Literal { lit: token::Lit::new(kind, symbol, suffix), span: self.call_site }
|
||||
}
|
||||
}
|
||||
|
||||
impl server::Types for Rustc<'_, '_> {
|
||||
type FreeFunctions = FreeFunctions;
|
||||
type TokenStream = TokenStream;
|
||||
type Literal = Literal;
|
||||
type SourceFile = Lrc<SourceFile>;
|
||||
type MultiSpan = Vec<Span>;
|
||||
type Diagnostic = Diagnostic;
|
||||
@ -352,6 +385,94 @@ impl server::FreeFunctions for Rustc<'_, '_> {
|
||||
fn track_path(&mut self, path: &str) {
|
||||
self.sess().file_depinfo.borrow_mut().insert(Symbol::intern(path));
|
||||
}
|
||||
|
||||
fn literal_from_str(&mut self, s: &str) -> Result<Literal<Self::Span, Self::Symbol>, ()> {
|
||||
let name = FileName::proc_macro_source_code(s);
|
||||
let mut parser = rustc_parse::new_parser_from_source_str(self.sess(), name, s.to_owned());
|
||||
|
||||
let first_span = parser.token.span.data();
|
||||
let minus_present = parser.eat(&token::BinOp(token::Minus));
|
||||
|
||||
let lit_span = parser.token.span.data();
|
||||
let token::Literal(mut lit) = parser.token.kind else {
|
||||
return Err(());
|
||||
};
|
||||
|
||||
// Check no comment or whitespace surrounding the (possibly negative)
|
||||
// literal, or more tokens after it.
|
||||
if (lit_span.hi.0 - first_span.lo.0) as usize != s.len() {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if minus_present {
|
||||
// If minus is present, check no comment or whitespace in between it
|
||||
// and the literal token.
|
||||
if first_span.hi.0 != lit_span.lo.0 {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
// Check literal is a kind we allow to be negated in a proc macro token.
|
||||
match lit.kind {
|
||||
token::LitKind::Bool
|
||||
| token::LitKind::Byte
|
||||
| token::LitKind::Char
|
||||
| token::LitKind::Str
|
||||
| token::LitKind::StrRaw(_)
|
||||
| token::LitKind::ByteStr
|
||||
| token::LitKind::ByteStrRaw(_)
|
||||
| token::LitKind::Err => return Err(()),
|
||||
token::LitKind::Integer | token::LitKind::Float => {}
|
||||
}
|
||||
|
||||
// Synthesize a new symbol that includes the minus sign.
|
||||
let symbol = Symbol::intern(&s[..1 + lit.symbol.as_str().len()]);
|
||||
lit = token::Lit::new(lit.kind, symbol, lit.suffix);
|
||||
}
|
||||
let token::Lit { kind, symbol, suffix } = lit;
|
||||
Ok(Literal {
|
||||
kind: FromInternal::from_internal(kind),
|
||||
symbol,
|
||||
suffix,
|
||||
span: self.call_site,
|
||||
})
|
||||
}
|
||||
|
||||
fn literal_subspan(
|
||||
&mut self,
|
||||
literal: Literal<Self::Span, Self::Symbol>,
|
||||
start: Bound<usize>,
|
||||
end: Bound<usize>,
|
||||
) -> Option<Self::Span> {
|
||||
let span = literal.span;
|
||||
let length = span.hi().to_usize() - span.lo().to_usize();
|
||||
|
||||
let start = match start {
|
||||
Bound::Included(lo) => lo,
|
||||
Bound::Excluded(lo) => lo.checked_add(1)?,
|
||||
Bound::Unbounded => 0,
|
||||
};
|
||||
|
||||
let end = match end {
|
||||
Bound::Included(hi) => hi.checked_add(1)?,
|
||||
Bound::Excluded(hi) => hi,
|
||||
Bound::Unbounded => length,
|
||||
};
|
||||
|
||||
// Bounds check the values, preventing addition overflow and OOB spans.
|
||||
if start > u32::MAX as usize
|
||||
|| end > u32::MAX as usize
|
||||
|| (u32::MAX - start as u32) < span.lo().to_u32()
|
||||
|| (u32::MAX - end as u32) < span.lo().to_u32()
|
||||
|| start >= end
|
||||
|| end > length
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let new_lo = span.lo() + BytePos::from_usize(start);
|
||||
let new_hi = span.lo() + BytePos::from_usize(end);
|
||||
Some(span.with_lo(new_lo).with_hi(new_hi))
|
||||
}
|
||||
}
|
||||
|
||||
impl server::TokenStream for Rustc<'_, '_> {
|
||||
@ -429,7 +550,7 @@ impl server::TokenStream for Rustc<'_, '_> {
|
||||
|
||||
fn from_token_tree(
|
||||
&mut self,
|
||||
tree: TokenTree<Self::TokenStream, Self::Span, Self::Symbol, Self::Literal>,
|
||||
tree: TokenTree<Self::TokenStream, Self::Span, Self::Symbol>,
|
||||
) -> Self::TokenStream {
|
||||
(tree, &mut *self).to_internal()
|
||||
}
|
||||
@ -437,7 +558,7 @@ impl server::TokenStream for Rustc<'_, '_> {
|
||||
fn concat_trees(
|
||||
&mut self,
|
||||
base: Option<Self::TokenStream>,
|
||||
trees: Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol, Self::Literal>>,
|
||||
trees: Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>>,
|
||||
) -> Self::TokenStream {
|
||||
let mut builder = tokenstream::TokenStreamBuilder::new();
|
||||
if let Some(base) = base {
|
||||
@ -467,164 +588,11 @@ impl server::TokenStream for Rustc<'_, '_> {
|
||||
fn into_trees(
|
||||
&mut self,
|
||||
stream: Self::TokenStream,
|
||||
) -> Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol, Self::Literal>> {
|
||||
) -> Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>> {
|
||||
FromInternal::from_internal((stream, self))
|
||||
}
|
||||
}
|
||||
|
||||
impl server::Literal for Rustc<'_, '_> {
|
||||
fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> {
|
||||
let name = FileName::proc_macro_source_code(s);
|
||||
let mut parser = rustc_parse::new_parser_from_source_str(self.sess(), name, s.to_owned());
|
||||
|
||||
let first_span = parser.token.span.data();
|
||||
let minus_present = parser.eat(&token::BinOp(token::Minus));
|
||||
|
||||
let lit_span = parser.token.span.data();
|
||||
let token::Literal(mut lit) = parser.token.kind else {
|
||||
return Err(());
|
||||
};
|
||||
|
||||
// Check no comment or whitespace surrounding the (possibly negative)
|
||||
// literal, or more tokens after it.
|
||||
if (lit_span.hi.0 - first_span.lo.0) as usize != s.len() {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if minus_present {
|
||||
// If minus is present, check no comment or whitespace in between it
|
||||
// and the literal token.
|
||||
if first_span.hi.0 != lit_span.lo.0 {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
// Check literal is a kind we allow to be negated in a proc macro token.
|
||||
match lit.kind {
|
||||
token::LitKind::Bool
|
||||
| token::LitKind::Byte
|
||||
| token::LitKind::Char
|
||||
| token::LitKind::Str
|
||||
| token::LitKind::StrRaw(_)
|
||||
| token::LitKind::ByteStr
|
||||
| token::LitKind::ByteStrRaw(_)
|
||||
| token::LitKind::Err => return Err(()),
|
||||
token::LitKind::Integer | token::LitKind::Float => {}
|
||||
}
|
||||
|
||||
// Synthesize a new symbol that includes the minus sign.
|
||||
let symbol = Symbol::intern(&s[..1 + lit.symbol.as_str().len()]);
|
||||
lit = token::Lit::new(lit.kind, symbol, lit.suffix);
|
||||
}
|
||||
|
||||
Ok(Literal { lit, span: self.call_site })
|
||||
}
|
||||
|
||||
fn to_string(&mut self, literal: &Self::Literal) -> String {
|
||||
literal.lit.to_string()
|
||||
}
|
||||
|
||||
fn debug_kind(&mut self, literal: &Self::Literal) -> String {
|
||||
format!("{:?}", literal.lit.kind)
|
||||
}
|
||||
|
||||
fn symbol(&mut self, literal: &Self::Literal) -> String {
|
||||
literal.lit.symbol.to_string()
|
||||
}
|
||||
|
||||
fn suffix(&mut self, literal: &Self::Literal) -> Option<String> {
|
||||
literal.lit.suffix.as_ref().map(Symbol::to_string)
|
||||
}
|
||||
|
||||
fn integer(&mut self, n: &str) -> Self::Literal {
|
||||
self.lit(token::Integer, Symbol::intern(n), None)
|
||||
}
|
||||
|
||||
fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal {
|
||||
self.lit(token::Integer, Symbol::intern(n), Some(Symbol::intern(kind)))
|
||||
}
|
||||
|
||||
fn float(&mut self, n: &str) -> Self::Literal {
|
||||
self.lit(token::Float, Symbol::intern(n), None)
|
||||
}
|
||||
|
||||
fn f32(&mut self, n: &str) -> Self::Literal {
|
||||
self.lit(token::Float, Symbol::intern(n), Some(sym::f32))
|
||||
}
|
||||
|
||||
fn f64(&mut self, n: &str) -> Self::Literal {
|
||||
self.lit(token::Float, Symbol::intern(n), Some(sym::f64))
|
||||
}
|
||||
|
||||
fn string(&mut self, string: &str) -> Self::Literal {
|
||||
let quoted = format!("{:?}", string);
|
||||
assert!(quoted.starts_with('"') && quoted.ends_with('"'));
|
||||
let symbol = "ed[1..quoted.len() - 1];
|
||||
self.lit(token::Str, Symbol::intern(symbol), None)
|
||||
}
|
||||
|
||||
fn character(&mut self, ch: char) -> Self::Literal {
|
||||
let quoted = format!("{:?}", ch);
|
||||
assert!(quoted.starts_with('\'') && quoted.ends_with('\''));
|
||||
let symbol = "ed[1..quoted.len() - 1];
|
||||
self.lit(token::Char, Symbol::intern(symbol), None)
|
||||
}
|
||||
|
||||
fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal {
|
||||
let string = bytes
|
||||
.iter()
|
||||
.cloned()
|
||||
.flat_map(ascii::escape_default)
|
||||
.map(Into::<char>::into)
|
||||
.collect::<String>();
|
||||
self.lit(token::ByteStr, Symbol::intern(&string), None)
|
||||
}
|
||||
|
||||
fn span(&mut self, literal: &Self::Literal) -> Self::Span {
|
||||
literal.span
|
||||
}
|
||||
|
||||
fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) {
|
||||
literal.span = span;
|
||||
}
|
||||
|
||||
fn subspan(
|
||||
&mut self,
|
||||
literal: &Self::Literal,
|
||||
start: Bound<usize>,
|
||||
end: Bound<usize>,
|
||||
) -> Option<Self::Span> {
|
||||
let span = literal.span;
|
||||
let length = span.hi().to_usize() - span.lo().to_usize();
|
||||
|
||||
let start = match start {
|
||||
Bound::Included(lo) => lo,
|
||||
Bound::Excluded(lo) => lo.checked_add(1)?,
|
||||
Bound::Unbounded => 0,
|
||||
};
|
||||
|
||||
let end = match end {
|
||||
Bound::Included(hi) => hi.checked_add(1)?,
|
||||
Bound::Excluded(hi) => hi,
|
||||
Bound::Unbounded => length,
|
||||
};
|
||||
|
||||
// Bounds check the values, preventing addition overflow and OOB spans.
|
||||
if start > u32::MAX as usize
|
||||
|| end > u32::MAX as usize
|
||||
|| (u32::MAX - start as u32) < span.lo().to_u32()
|
||||
|| (u32::MAX - end as u32) < span.lo().to_u32()
|
||||
|| start >= end
|
||||
|| end > length
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let new_lo = span.lo() + BytePos::from_usize(start);
|
||||
let new_hi = span.lo() + BytePos::from_usize(end);
|
||||
Some(span.with_lo(new_lo).with_hi(new_hi))
|
||||
}
|
||||
}
|
||||
|
||||
impl server::SourceFile for Rustc<'_, '_> {
|
||||
fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
|
||||
Lrc::ptr_eq(file1, file2)
|
||||
|
@ -175,7 +175,6 @@ define_handles! {
|
||||
'owned:
|
||||
FreeFunctions,
|
||||
TokenStream,
|
||||
Literal,
|
||||
SourceFile,
|
||||
MultiSpan,
|
||||
Diagnostic,
|
||||
@ -196,25 +195,6 @@ impl Clone for TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Literal {
|
||||
fn clone(&self) -> Self {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Literal {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Literal")
|
||||
// format the kind without quotes, as in `kind: Float`
|
||||
.field("kind", &format_args!("{}", &self.debug_kind()))
|
||||
.field("symbol", &self.symbol())
|
||||
// format `Some("...")` on one line even in {:#?} mode
|
||||
.field("suffix", &format_args!("{:?}", &self.suffix()))
|
||||
.field("span", &self.span())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for SourceFile {
|
||||
fn clone(&self) -> Self {
|
||||
self.clone()
|
||||
|
@ -56,6 +56,8 @@ macro_rules! with_api {
|
||||
fn drop($self: $S::FreeFunctions);
|
||||
fn track_env_var(var: &str, value: Option<&str>);
|
||||
fn track_path(path: &str);
|
||||
fn literal_from_str(s: &str) -> Result<Literal<$S::Span, $S::Symbol>, ()>;
|
||||
fn literal_subspan(lit: Literal<$S::Span, $S::Symbol>, start: Bound<usize>, end: Bound<usize>) -> Option<$S::Span>;
|
||||
},
|
||||
TokenStream {
|
||||
fn drop($self: $S::TokenStream);
|
||||
@ -65,11 +67,11 @@ macro_rules! with_api {
|
||||
fn from_str(src: &str) -> $S::TokenStream;
|
||||
fn to_string($self: &$S::TokenStream) -> String;
|
||||
fn from_token_tree(
|
||||
tree: TokenTree<$S::TokenStream, $S::Span, $S::Symbol, $S::Literal>,
|
||||
tree: TokenTree<$S::TokenStream, $S::Span, $S::Symbol>,
|
||||
) -> $S::TokenStream;
|
||||
fn concat_trees(
|
||||
base: Option<$S::TokenStream>,
|
||||
trees: Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol, $S::Literal>>,
|
||||
trees: Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>,
|
||||
) -> $S::TokenStream;
|
||||
fn concat_streams(
|
||||
base: Option<$S::TokenStream>,
|
||||
@ -77,31 +79,7 @@ macro_rules! with_api {
|
||||
) -> $S::TokenStream;
|
||||
fn into_trees(
|
||||
$self: $S::TokenStream
|
||||
) -> Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol, $S::Literal>>;
|
||||
},
|
||||
Literal {
|
||||
fn drop($self: $S::Literal);
|
||||
fn clone($self: &$S::Literal) -> $S::Literal;
|
||||
fn from_str(s: &str) -> Result<$S::Literal, ()>;
|
||||
fn to_string($self: &$S::Literal) -> String;
|
||||
fn debug_kind($self: &$S::Literal) -> String;
|
||||
fn symbol($self: &$S::Literal) -> String;
|
||||
fn suffix($self: &$S::Literal) -> Option<String>;
|
||||
fn integer(n: &str) -> $S::Literal;
|
||||
fn typed_integer(n: &str, kind: &str) -> $S::Literal;
|
||||
fn float(n: &str) -> $S::Literal;
|
||||
fn f32(n: &str) -> $S::Literal;
|
||||
fn f64(n: &str) -> $S::Literal;
|
||||
fn string(string: &str) -> $S::Literal;
|
||||
fn character(ch: char) -> $S::Literal;
|
||||
fn byte_string(bytes: &[u8]) -> $S::Literal;
|
||||
fn span($self: &$S::Literal) -> $S::Span;
|
||||
fn set_span($self: &mut $S::Literal, span: $S::Span);
|
||||
fn subspan(
|
||||
$self: &$S::Literal,
|
||||
start: Bound<usize>,
|
||||
end: Bound<usize>,
|
||||
) -> Option<$S::Span>;
|
||||
) -> Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>;
|
||||
},
|
||||
SourceFile {
|
||||
fn drop($self: $S::SourceFile);
|
||||
@ -332,6 +310,7 @@ mark_noop! {
|
||||
u8,
|
||||
usize,
|
||||
Delimiter,
|
||||
LitKind,
|
||||
Level,
|
||||
LineColumn,
|
||||
Spacing,
|
||||
@ -361,6 +340,33 @@ rpc_encode_decode!(
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum LitKind {
|
||||
Byte,
|
||||
Char,
|
||||
Integer,
|
||||
Float,
|
||||
Str,
|
||||
StrRaw(u8),
|
||||
ByteStr,
|
||||
ByteStrRaw(u8),
|
||||
Err,
|
||||
}
|
||||
|
||||
rpc_encode_decode!(
|
||||
enum LitKind {
|
||||
Byte,
|
||||
Char,
|
||||
Integer,
|
||||
Float,
|
||||
Str,
|
||||
StrRaw(n),
|
||||
ByteStr,
|
||||
ByteStrRaw(n),
|
||||
Err,
|
||||
}
|
||||
);
|
||||
|
||||
macro_rules! mark_compound {
|
||||
(struct $name:ident <$($T:ident),+> { $($field:ident),* $(,)? }) => {
|
||||
impl<$($T: Mark),+> Mark for $name <$($T),+> {
|
||||
@ -477,16 +483,26 @@ pub struct Ident<Span, Symbol> {
|
||||
|
||||
compound_traits!(struct Ident<Span, Symbol> { sym, is_raw, span });
|
||||
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub struct Literal<Span, Symbol> {
|
||||
pub kind: LitKind,
|
||||
pub symbol: Symbol,
|
||||
pub suffix: Option<Symbol>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
compound_traits!(struct Literal<Sp, Sy> { kind, symbol, suffix, span });
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum TokenTree<TokenStream, Span, Symbol, Literal> {
|
||||
pub enum TokenTree<TokenStream, Span, Symbol> {
|
||||
Group(Group<TokenStream, Span>),
|
||||
Punct(Punct<Span>),
|
||||
Ident(Ident<Span, Symbol>),
|
||||
Literal(Literal),
|
||||
Literal(Literal<Span, Symbol>),
|
||||
}
|
||||
|
||||
compound_traits!(
|
||||
enum TokenTree<TokenStream, Span, Symbol, Literal> {
|
||||
enum TokenTree<TokenStream, Span, Symbol> {
|
||||
Group(tt),
|
||||
Punct(tt),
|
||||
Ident(tt),
|
||||
|
@ -8,7 +8,6 @@ use super::client::HandleStore;
|
||||
pub trait Types {
|
||||
type FreeFunctions: 'static;
|
||||
type TokenStream: 'static + Clone;
|
||||
type Literal: 'static + Clone;
|
||||
type SourceFile: 'static + Clone;
|
||||
type MultiSpan: 'static;
|
||||
type Diagnostic: 'static;
|
||||
|
@ -215,12 +215,7 @@ pub use quote::{quote, quote_span};
|
||||
|
||||
fn tree_to_bridge_tree(
|
||||
tree: TokenTree,
|
||||
) -> bridge::TokenTree<
|
||||
bridge::client::TokenStream,
|
||||
bridge::client::Span,
|
||||
bridge::client::Symbol,
|
||||
bridge::client::Literal,
|
||||
> {
|
||||
) -> bridge::TokenTree<bridge::client::TokenStream, bridge::client::Span, bridge::client::Symbol> {
|
||||
match tree {
|
||||
TokenTree::Group(tt) => bridge::TokenTree::Group(tt.0),
|
||||
TokenTree::Punct(tt) => bridge::TokenTree::Punct(tt.0),
|
||||
@ -245,7 +240,6 @@ struct ConcatTreesHelper {
|
||||
bridge::client::TokenStream,
|
||||
bridge::client::Span,
|
||||
bridge::client::Symbol,
|
||||
bridge::client::Literal,
|
||||
>,
|
||||
>,
|
||||
}
|
||||
@ -372,7 +366,6 @@ pub mod token_stream {
|
||||
bridge::client::TokenStream,
|
||||
bridge::client::Span,
|
||||
bridge::client::Symbol,
|
||||
bridge::client::Literal,
|
||||
>,
|
||||
>,
|
||||
);
|
||||
@ -1147,7 +1140,7 @@ impl fmt::Debug for Ident {
|
||||
/// Boolean literals like `true` and `false` do not belong here, they are `Ident`s.
|
||||
#[derive(Clone)]
|
||||
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
||||
pub struct Literal(bridge::client::Literal);
|
||||
pub struct Literal(bridge::Literal<bridge::client::Span, bridge::client::Symbol>);
|
||||
|
||||
macro_rules! suffixed_int_literals {
|
||||
($($name:ident => $kind:ident,)*) => ($(
|
||||
@ -1164,7 +1157,12 @@ macro_rules! suffixed_int_literals {
|
||||
/// below.
|
||||
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
||||
pub fn $name(n: $kind) -> Literal {
|
||||
Literal(bridge::client::Literal::typed_integer(&n.to_string(), stringify!($kind)))
|
||||
Literal(bridge::Literal {
|
||||
kind: bridge::LitKind::Integer,
|
||||
symbol: bridge::client::Symbol::new(&n.to_string()),
|
||||
suffix: Some(bridge::client::Symbol::new(stringify!($kind))),
|
||||
span: Span::call_site().0,
|
||||
})
|
||||
}
|
||||
)*)
|
||||
}
|
||||
@ -1186,12 +1184,26 @@ macro_rules! unsuffixed_int_literals {
|
||||
/// below.
|
||||
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
||||
pub fn $name(n: $kind) -> Literal {
|
||||
Literal(bridge::client::Literal::integer(&n.to_string()))
|
||||
Literal(bridge::Literal {
|
||||
kind: bridge::LitKind::Integer,
|
||||
symbol: bridge::client::Symbol::new(&n.to_string()),
|
||||
suffix: None,
|
||||
span: Span::call_site().0,
|
||||
})
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
impl Literal {
|
||||
fn new(kind: bridge::LitKind, value: &str, suffix: Option<&str>) -> Self {
|
||||
Literal(bridge::Literal {
|
||||
kind,
|
||||
symbol: bridge::client::Symbol::new(value),
|
||||
suffix: suffix.map(bridge::client::Symbol::new),
|
||||
span: Span::call_site().0,
|
||||
})
|
||||
}
|
||||
|
||||
suffixed_int_literals! {
|
||||
u8_suffixed => u8,
|
||||
u16_suffixed => u16,
|
||||
@ -1243,7 +1255,7 @@ impl Literal {
|
||||
if !repr.contains('.') {
|
||||
repr.push_str(".0");
|
||||
}
|
||||
Literal(bridge::client::Literal::float(&repr))
|
||||
Literal::new(bridge::LitKind::Float, &repr, None)
|
||||
}
|
||||
|
||||
/// Creates a new suffixed floating-point literal.
|
||||
@ -1264,7 +1276,7 @@ impl Literal {
|
||||
if !n.is_finite() {
|
||||
panic!("Invalid float literal {n}");
|
||||
}
|
||||
Literal(bridge::client::Literal::f32(&n.to_string()))
|
||||
Literal::new(bridge::LitKind::Float, &n.to_string(), Some("f32"))
|
||||
}
|
||||
|
||||
/// Creates a new unsuffixed floating-point literal.
|
||||
@ -1288,7 +1300,7 @@ impl Literal {
|
||||
if !repr.contains('.') {
|
||||
repr.push_str(".0");
|
||||
}
|
||||
Literal(bridge::client::Literal::float(&repr))
|
||||
Literal::new(bridge::LitKind::Float, &repr, None)
|
||||
}
|
||||
|
||||
/// Creates a new suffixed floating-point literal.
|
||||
@ -1309,37 +1321,49 @@ impl Literal {
|
||||
if !n.is_finite() {
|
||||
panic!("Invalid float literal {n}");
|
||||
}
|
||||
Literal(bridge::client::Literal::f64(&n.to_string()))
|
||||
Literal::new(bridge::LitKind::Float, &n.to_string(), Some("f64"))
|
||||
}
|
||||
|
||||
/// String literal.
|
||||
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
||||
pub fn string(string: &str) -> Literal {
|
||||
Literal(bridge::client::Literal::string(string))
|
||||
let quoted = format!("{:?}", string);
|
||||
assert!(quoted.starts_with('"') && quoted.ends_with('"'));
|
||||
let symbol = "ed[1..quoted.len() - 1];
|
||||
Literal::new(bridge::LitKind::Str, symbol, None)
|
||||
}
|
||||
|
||||
/// Character literal.
|
||||
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
||||
pub fn character(ch: char) -> Literal {
|
||||
Literal(bridge::client::Literal::character(ch))
|
||||
let quoted = format!("{:?}", ch);
|
||||
assert!(quoted.starts_with('\'') && quoted.ends_with('\''));
|
||||
let symbol = "ed[1..quoted.len() - 1];
|
||||
Literal::new(bridge::LitKind::Char, symbol, None)
|
||||
}
|
||||
|
||||
/// Byte string literal.
|
||||
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
||||
pub fn byte_string(bytes: &[u8]) -> Literal {
|
||||
Literal(bridge::client::Literal::byte_string(bytes))
|
||||
let string = bytes
|
||||
.iter()
|
||||
.cloned()
|
||||
.flat_map(std::ascii::escape_default)
|
||||
.map(Into::<char>::into)
|
||||
.collect::<String>();
|
||||
Literal::new(bridge::LitKind::ByteStr, &string, None)
|
||||
}
|
||||
|
||||
/// Returns the span encompassing this literal.
|
||||
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
||||
pub fn span(&self) -> Span {
|
||||
Span(self.0.span())
|
||||
Span(self.0.span)
|
||||
}
|
||||
|
||||
/// Configures the span associated for this literal.
|
||||
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
||||
pub fn set_span(&mut self, span: Span) {
|
||||
self.0.set_span(span.0);
|
||||
self.0.span = span.0;
|
||||
}
|
||||
|
||||
/// Returns a `Span` that is a subset of `self.span()` containing only the
|
||||
@ -1355,7 +1379,55 @@ impl Literal {
|
||||
// was 'c' or whether it was '\u{63}'.
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> {
|
||||
self.0.subspan(range.start_bound().cloned(), range.end_bound().cloned()).map(Span)
|
||||
bridge::client::FreeFunctions::literal_subspan(
|
||||
self.0.clone(),
|
||||
range.start_bound().cloned(),
|
||||
range.end_bound().cloned(),
|
||||
)
|
||||
.map(Span)
|
||||
}
|
||||
|
||||
fn with_symbol_and_suffix<R>(&self, f: impl FnOnce(&str, &str) -> R) -> R {
|
||||
self.0.symbol.with(|symbol| match self.0.suffix {
|
||||
Some(suffix) => suffix.with(|suffix| f(symbol, suffix)),
|
||||
None => f(symbol, ""),
|
||||
})
|
||||
}
|
||||
|
||||
/// 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]),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1374,19 +1446,17 @@ impl FromStr for Literal {
|
||||
type Err = LexError;
|
||||
|
||||
fn from_str(src: &str) -> Result<Self, LexError> {
|
||||
match bridge::client::Literal::from_str(src) {
|
||||
match bridge::client::FreeFunctions::literal_from_str(src) {
|
||||
Ok(literal) => Ok(Literal(literal)),
|
||||
Err(()) => Err(LexError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// N.B., the bridge only provides `to_string`, implement `fmt::Display`
|
||||
// based on it (the reverse of the usual relationship between the two).
|
||||
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
|
||||
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
||||
impl ToString for Literal {
|
||||
fn to_string(&self) -> String {
|
||||
self.0.to_string()
|
||||
self.with_stringify_parts(|parts| parts.concat())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1395,14 +1465,26 @@ impl ToString for Literal {
|
||||
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
||||
impl fmt::Display for Literal {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(&self.to_string())
|
||||
self.with_stringify_parts(|parts| {
|
||||
for part in parts {
|
||||
fmt::Display::fmt(part, f)?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
||||
impl fmt::Debug for Literal {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
f.debug_struct("Literal")
|
||||
// format the kind on one line even in {:#?} mode
|
||||
.field("kind", &format_args!("{:?}", &self.0.kind))
|
||||
.field("symbol", &self.0.symbol)
|
||||
// format `Some("...")` on one line even in {:#?} mode
|
||||
.field("suffix", &format_args!("{:?}", &self.0.suffix))
|
||||
.field("span", &self.0.span)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user