Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Support negative numbers in Literal::from_str
  • Loading branch information
dtolnay committed Jul 18, 2021
1 parent 331da58 commit 55ff45a
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 22 deletions.
63 changes: 41 additions & 22 deletions compiler/rustc_expand/src/proc_macro_server.rs
@@ -1,7 +1,7 @@
use crate::base::{ExtCtxt, ResolverExpand};

use rustc_ast as ast;
use rustc_ast::token::{self, Nonterminal, NtIdent, TokenKind};
use rustc_ast::token::{self, Nonterminal, NtIdent};
use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens};
use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
use rustc_ast_pretty::pprust;
Expand Down Expand Up @@ -537,30 +537,49 @@ impl server::Ident for Rustc<'_> {

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 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 mut lit = match parser.token.kind {
token::Literal(lit) => lit,
_ => 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.

// 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(());
}
let lit = match token.kind {
TokenKind::Literal(lit) => lit,
_ => 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.len()]);
lit = token::Lit::new(lit.kind, symbol, lit.suffix);
}

Ok(Literal { lit, span: self.call_site })
}
fn debug_kind(&mut self, literal: &Self::Literal) -> String {
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Expand Up @@ -1588,6 +1588,10 @@ impl Symbol {
self.0.as_u32()
}

pub fn len(self) -> usize {
with_interner(|interner| interner.get(self).len())
}

pub fn is_empty(self) -> bool {
self == kw::Empty
}
Expand Down
11 changes: 11 additions & 0 deletions src/test/ui/proc-macro/auxiliary/api/parse.rs
@@ -1,9 +1,15 @@
use proc_macro::Literal;

pub fn test() {
test_display_literal();
test_parse_literal();
}

fn test_display_literal() {
assert_eq!(Literal::isize_unsuffixed(-10).to_string(), "- 10");
assert_eq!(Literal::isize_suffixed(-10).to_string(), "- 10isize");
}

fn test_parse_literal() {
assert_eq!("1".parse::<Literal>().unwrap().to_string(), "1");
assert_eq!("1.0".parse::<Literal>().unwrap().to_string(), "1.0");
Expand All @@ -12,12 +18,17 @@ fn test_parse_literal() {
assert_eq!("b\"\"".parse::<Literal>().unwrap().to_string(), "b\"\"");
assert_eq!("r##\"\"##".parse::<Literal>().unwrap().to_string(), "r##\"\"##");
assert_eq!("10ulong".parse::<Literal>().unwrap().to_string(), "10ulong");
assert_eq!("-10ulong".parse::<Literal>().unwrap().to_string(), "- 10ulong");

assert!("true".parse::<Literal>().is_err());
assert!(".8".parse::<Literal>().is_err());
assert!("0 1".parse::<Literal>().is_err());
assert!("'a".parse::<Literal>().is_err());
assert!(" 0".parse::<Literal>().is_err());
assert!("0 ".parse::<Literal>().is_err());
assert!("/* comment */0".parse::<Literal>().is_err());
assert!("0/* comment */".parse::<Literal>().is_err());
assert!("0// comment".parse::<Literal>().is_err());
assert!("- 10".parse::<Literal>().is_err());
assert!("-'x'".parse::<Literal>().is_err());
}

0 comments on commit 55ff45a

Please sign in to comment.