diff options
author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2018-05-14 00:01:56 +0300 |
---|---|---|
committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2018-05-15 23:54:08 +0300 |
commit | c1061254317ac747d2bf5901329545f4cec5ebcb (patch) | |
tree | 4abe39c1bf4c5db072c168ce019c195763e0920b /src | |
parent | 5b820a694c0fd8392092c3f0301537aafe92cce2 (diff) | |
download | rust-c1061254317ac747d2bf5901329545f4cec5ebcb.tar.gz |
Represent lifetimes as two joint tokens in proc macros
Diffstat (limited to 'src')
-rw-r--r-- | src/libproc_macro/lib.rs | 34 | ||||
-rw-r--r-- | src/librustc/ich/impls_syntax.rs | 1 | ||||
-rw-r--r-- | src/librustdoc/html/highlight.rs | 2 | ||||
-rw-r--r-- | src/libsyntax/ext/quote.rs | 1 | ||||
-rw-r--r-- | src/libsyntax/parse/lexer/mod.rs | 5 | ||||
-rw-r--r-- | src/libsyntax/parse/token.rs | 6 | ||||
-rw-r--r-- | src/libsyntax/print/pprust.rs | 1 | ||||
-rw-r--r-- | src/test/run-pass-fulldeps/proc-macro/auxiliary/lifetimes.rs | 36 | ||||
-rw-r--r-- | src/test/run-pass-fulldeps/proc-macro/lifetimes.rs | 36 | ||||
-rw-r--r-- | src/test/ui-fulldeps/auxiliary/lifetimes.rs | 30 | ||||
-rw-r--r-- | src/test/ui-fulldeps/lifetimes.rs | 19 | ||||
-rw-r--r-- | src/test/ui-fulldeps/lifetimes.stderr | 8 |
12 files changed, 158 insertions, 21 deletions
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index bf99a14a454..267922bf4a1 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -487,7 +487,7 @@ impl PartialEq<FileName> for SourceFile { pub enum TokenTree { /// A token stream surrounded by bracket delimiters. Group(Group), - /// An identifier or lifetime identifier. + /// An identifier. Ident(Ident), /// A single punctuation character (`+`, `,`, `$`, etc.). Punct(Punct), @@ -702,9 +702,10 @@ impl !Sync for Punct {} #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[unstable(feature = "proc_macro", issue = "38356")] pub enum Spacing { - /// e.g. `+` is `Alone` in `+ =`, `+ident` or `+()`. + /// E.g. `+` is `Alone` in `+ =`, `+ident` or `+()`. Alone, - /// e.g. `+` is `Joint` in `+=` or `+#`. + /// E.g. `+` is `Joint` in `+=` or `'#`. + /// Additionally, single quote `'` can join with identifiers to form lifetimes `'ident`. Joint, } @@ -717,8 +718,8 @@ impl Punct { /// which can be further configured with the `set_span` method below. #[unstable(feature = "proc_macro", issue = "38356")] pub fn new(ch: char, spacing: Spacing) -> Punct { - const LEGAL_CHARS: &[char] = &['=', '<', '>', '!', '~', '+', '-', '*', '/', '%', - '^', '&', '|', '@', '.', ',', ';', ':', '#', '$', '?']; + const LEGAL_CHARS: &[char] = &['=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^', + '&', '|', '@', '.', ',', ';', ':', '#', '$', '?', '\'']; if !LEGAL_CHARS.contains(&ch) { panic!("unsupported character `{:?}`", ch) } @@ -766,7 +767,7 @@ impl fmt::Display for Punct { } } -/// An identifier (`ident`) or lifetime identifier (`'ident`). +/// An identifier (`ident`). #[derive(Clone, Debug)] #[unstable(feature = "proc_macro", issue = "38356")] pub struct Ident { @@ -783,7 +784,7 @@ impl !Sync for Ident {} impl Ident { /// Creates a new `Ident` with the given `string` as well as the specified /// `span`. - /// The `string` argument must be a valid identifier or lifetime identifier permitted by the + /// The `string` argument must be a valid identifier permitted by the /// language, otherwise the function will panic. /// /// Note that `span`, currently in rustc, configures the hygiene information @@ -817,8 +818,7 @@ impl Ident { pub fn new_raw(string: &str, span: Span) -> Ident { let mut ident = Ident::new(string, span); if ident.sym == keywords::Underscore.name() || - token::is_path_segment_keyword(ast::Ident::with_empty_ctxt(ident.sym)) || - ident.sym.as_str().starts_with("\'") { + token::is_path_segment_keyword(ast::Ident::with_empty_ctxt(ident.sym)) { panic!("`{:?}` is not a valid raw identifier", string) } ident.is_raw = true; @@ -1211,13 +1211,19 @@ impl TokenTree { Pound => op!('#'), Dollar => op!('$'), Question => op!('?'), + SingleQuote => op!('\''), - Ident(ident, false) | Lifetime(ident) => { + Ident(ident, false) => { tt!(self::Ident::new(&ident.name.as_str(), Span(span))) } Ident(ident, true) => { tt!(self::Ident::new_raw(&ident.name.as_str(), Span(span))) } + Lifetime(ident) => { + let ident = ident.without_first_quote(); + stack.push(tt!(self::Ident::new(&ident.name.as_str(), Span(span)))); + tt!(Punct::new('\'', Spacing::Joint)) + } Literal(lit, suffix) => tt!(self::Literal { lit, suffix, span: Span(span) }), DocComment(c) => { let style = comments::doc_comment_style(&c.as_str()); @@ -1260,12 +1266,7 @@ impl TokenTree { }).into(); }, self::TokenTree::Ident(tt) => { - let ident = ast::Ident::new(tt.sym, tt.span.0); - let token = if tt.sym.as_str().starts_with("'") { - Lifetime(ident) - } else { - Ident(ident, tt.is_raw) - }; + let token = Ident(ast::Ident::new(tt.sym, tt.span.0), tt.is_raw); return TokenTree::Token(tt.span.0, token).into(); } self::TokenTree::Literal(self::Literal { @@ -1324,6 +1325,7 @@ impl TokenTree { '#' => Pound, '$' => Dollar, '?' => Question, + '\'' => SingleQuote, _ => unreachable!(), }; diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 1cf9b7bf478..f56d701b028 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -314,6 +314,7 @@ fn hash_token<'a, 'gcx, W: StableHasherResult>( token::Token::Pound | token::Token::Dollar | token::Token::Question | + token::Token::SingleQuote | token::Token::Whitespace | token::Token::Comment | token::Token::Eof => {} diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index cfa3f5a4e0b..cff89b03e3d 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -353,7 +353,7 @@ impl<'a> Classifier<'a> { token::Lifetime(..) => Class::Lifetime, token::Eof | token::Interpolated(..) | - token::Tilde | token::At | token::DotEq => Class::None, + token::Tilde | token::At | token::DotEq | token::SingleQuote => Class::None, }; // Anything that didn't return above is the simple case where we the diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index eeed291c0ca..a6e6ccde72c 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -711,6 +711,7 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> { token::Pound => "Pound", token::Dollar => "Dollar", token::Question => "Question", + token::SingleQuote => "SingleQuote", token::Eof => "Eof", token::Whitespace | token::Comment | token::Shebang(_) => { diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 4da7b8e93d9..3e22598043a 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1773,10 +1773,7 @@ fn ident_continue(c: Option<char>) -> bool { // The string is a valid identifier or a lifetime identifier. pub fn is_valid_ident(s: &str) -> bool { let mut chars = s.chars(); - match chars.next() { - Some('\'') => ident_start(chars.next()) && chars.all(|ch| ident_continue(Some(ch))), - ch => ident_start(ch) && chars.all(|ch| ident_continue(Some(ch))) - } + ident_start(chars.next()) && chars.all(|ch| ident_continue(Some(ch))) } #[cfg(test)] diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 6bcc1b0f026..a1c056cbb2c 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -210,6 +210,8 @@ pub enum Token { Pound, Dollar, Question, + /// Used by proc macros for representing lifetimes, not generated by lexer right now. + SingleQuote, /// An opening delimiter, eg. `{` OpenDelim(DelimToken), /// A closing delimiter, eg. `}` @@ -513,6 +515,10 @@ impl Token { Colon => ModSep, _ => return None, }, + SingleQuote => match joint { + Ident(ident, false) => Lifetime(ident), + _ => return None, + }, Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotEq | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 99a6fcf170d..8e33fa08083 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -224,6 +224,7 @@ pub fn token_to_string(tok: &Token) -> String { token::Pound => "#".to_string(), token::Dollar => "$".to_string(), token::Question => "?".to_string(), + token::SingleQuote => "'".to_string(), /* Literals */ token::Literal(lit, suf) => { diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/lifetimes.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/lifetimes.rs new file mode 100644 index 00000000000..f31f57b442a --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/lifetimes.rs @@ -0,0 +1,36 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![feature(proc_macro)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::*; + +#[proc_macro] +pub fn lifetimes_bang(input: TokenStream) -> TokenStream { + // Roundtrip through token trees + input.into_iter().collect() +} + +#[proc_macro_attribute] +pub fn lifetimes_attr(_: TokenStream, input: TokenStream) -> TokenStream { + // Roundtrip through AST + input +} + +#[proc_macro_derive(Lifetimes)] +pub fn lifetimes_derive(input: TokenStream) -> TokenStream { + // Roundtrip through a string + format!("mod m {{ {} }}", input).parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/proc-macro/lifetimes.rs b/src/test/run-pass-fulldeps/proc-macro/lifetimes.rs new file mode 100644 index 00000000000..0bcb23cc8bb --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/lifetimes.rs @@ -0,0 +1,36 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:lifetimes.rs +// ignore-stage1 + +#![feature(proc_macro)] + +extern crate lifetimes; +use lifetimes::*; + +lifetimes_bang! { + fn bang<'a>() -> &'a u8 { &0 } +} + +#[lifetimes_attr] +fn attr<'a>() -> &'a u8 { &1 } + +#[derive(Lifetimes)] +pub struct Lifetimes<'a> { + pub field: &'a u8, +} + +fn main() { + assert_eq!(bang::<'static>(), &0); + assert_eq!(attr::<'static>(), &1); + let l1 = Lifetimes { field: &0 }; + let l2 = m::Lifetimes { field: &1 }; +} diff --git a/src/test/ui-fulldeps/auxiliary/lifetimes.rs b/src/test/ui-fulldeps/auxiliary/lifetimes.rs new file mode 100644 index 00000000000..ecf0a56edf7 --- /dev/null +++ b/src/test/ui-fulldeps/auxiliary/lifetimes.rs @@ -0,0 +1,30 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![feature(proc_macro)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::*; + +#[proc_macro] +pub fn single_quote_alone(_: TokenStream) -> TokenStream { + // `&'a u8`, but the `'` token is not joint + let trees: Vec<TokenTree> = vec![ + Punct::new('&', Spacing::Alone).into(), + Punct::new('\'', Spacing::Alone).into(), + Ident::new("a", Span::call_site()).into(), + Ident::new("u8", Span::call_site()).into(), + ]; + trees.into_iter().collect() +} diff --git a/src/test/ui-fulldeps/lifetimes.rs b/src/test/ui-fulldeps/lifetimes.rs new file mode 100644 index 00000000000..6e88143d637 --- /dev/null +++ b/src/test/ui-fulldeps/lifetimes.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:lifetimes.rs + +#![feature(proc_macro, proc_macro_non_items)] + +extern crate lifetimes; + +use lifetimes::*; + +type A = single_quote_alone!(); //~ ERROR expected type, found `'` diff --git a/src/test/ui-fulldeps/lifetimes.stderr b/src/test/ui-fulldeps/lifetimes.stderr new file mode 100644 index 00000000000..6baf2b16998 --- /dev/null +++ b/src/test/ui-fulldeps/lifetimes.stderr @@ -0,0 +1,8 @@ +error: expected type, found `'` + --> $DIR/lifetimes.rs:19:10 + | +LL | type A = single_quote_alone!(); //~ ERROR expected type, found `'` + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + |