impl FromStr for proc_macro::Literal

This commit is contained in:
David Tolnay 2021-04-29 12:08:35 -07:00
parent 965bce4834
commit 34585cb678
No known key found for this signature in database
GPG key ID: F9BA143B95FF6D82
3 changed files with 70 additions and 3 deletions

View file

@ -1,9 +1,7 @@
use crate::base::{ExtCtxt, ResolverExpand};
use rustc_ast as ast;
use rustc_ast::token;
use rustc_ast::token::Nonterminal;
use rustc_ast::token::NtIdent;
use rustc_ast::token::{self, Nonterminal, NtIdent, TokenKind};
use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens};
use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
use rustc_ast_pretty::pprust;
@ -541,6 +539,33 @@ fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident {
}
impl server::Literal for Rustc<'_> {
fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> {
let override_span = None;
let stream = parse_stream_from_source_str(
FileName::proc_macro_source_code(s),
s.to_owned(),
self.sess,
override_span,
);
if stream.len() != 1 {
return Err(());
}
let tree = stream.into_trees().next().unwrap();
let token = match tree {
tokenstream::TokenTree::Token(token) => token,
tokenstream::TokenTree::Delimited { .. } => return Err(()),
};
let span_data = token.span.data();
if (span_data.hi.0 - span_data.lo.0) as usize != s.len() {
// There is a comment or whitespace adjacent to the literal.
return Err(());
}
let lit = match token.kind {
TokenKind::Literal(lit) => lit,
_ => return Err(()),
};
Ok(Literal { lit, span: self.call_site })
}
fn debug_kind(&mut self, literal: &Self::Literal) -> String {
format!("{:?}", literal.lit.kind)
}

View file

@ -107,6 +107,7 @@ fn next(
Literal {
fn drop($self: $S::Literal);
fn clone($self: &$S::Literal) -> $S::Literal;
fn from_str(s: &str) -> Result<$S::Literal, ()>;
fn debug_kind($self: &$S::Literal) -> String;
fn symbol($self: &$S::Literal) -> String;
fn suffix($self: &$S::Literal) -> Option<String>;
@ -315,6 +316,19 @@ fn unmark(self) -> Self::Unmarked {
}
}
impl<T: Mark, E: Mark> Mark for Result<T, E> {
type Unmarked = Result<T::Unmarked, E::Unmarked>;
fn mark(unmarked: Self::Unmarked) -> Self {
unmarked.map(T::mark).map_err(E::mark)
}
}
impl<T: Unmark, E: Unmark> Unmark for Result<T, E> {
type Unmarked = Result<T::Unmarked, E::Unmarked>;
fn unmark(self) -> Self::Unmarked {
self.map(T::unmark).map_err(E::unmark)
}
}
macro_rules! mark_noop {
($($ty:ty),* $(,)?) => {
$(

View file

@ -91,6 +91,12 @@ pub struct LexError {
_inner: (),
}
impl LexError {
fn new() -> Self {
LexError { _inner: () }
}
}
#[stable(feature = "proc_macro_lexerror_impls", since = "1.44.0")]
impl fmt::Display for LexError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -1171,6 +1177,28 @@ fn cloned_bound<T: Clone>(bound: Bound<&T>) -> Bound<T> {
}
}
/// Parse a single literal from its stringified representation.
///
/// In order to parse successfully, the input string must not contain anything
/// but the literal token. Specifically, it must not contain whitespace or
/// comments in addition to the literal.
///
/// The resulting literal token will have a `Span::call_site()` span.
///
/// NOTE: some errors may cause panics instead of returning `LexError`. We
/// reserve the right to change these errors into `LexError`s later.
#[stable(feature = "proc_macro_literal_parse", since = "1.54.0")]
impl FromStr for Literal {
type Err = LexError;
fn from_str(src: &str) -> Result<Self, LexError> {
match bridge::client::Literal::from_str(src) {
Ok(literal) => Ok(Literal(literal)),
Err(()) => Err(LexError::new()),
}
}
}
// 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")]