From 9b0be244a0ec426980d4985544caf1cfe6a80c19 Mon Sep 17 00:00:00 2001 From: Diggory Blake Date: Mon, 18 May 2015 23:37:50 +0100 Subject: [PATCH] Add macro lifetime specifier Allows accepting a lifetime as a parameter to a macro Fix line wrapping. Rename "lifetime" to "life" to avoid conflict with future keyword. --- src/libsyntax/ext/tt/macro_parser.rs | 10 +++++++++- src/libsyntax/ext/tt/macro_rules.rs | 4 ++-- src/libsyntax/ext/tt/transcribe.rs | 7 ++++++- src/libsyntax/fold.rs | 2 ++ src/libsyntax/parse/parser.rs | 3 +++ src/libsyntax/parse/token.rs | 2 ++ src/libsyntax/print/pprust.rs | 2 ++ src/test/run-pass/macro-interpolation.rs | 6 ++++-- 8 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 5521c68e75c69..0db1d9e0a9219 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -540,6 +540,14 @@ pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal { &token_str[..]))) } }, + "life" => match p.token { + token::Lifetime(sn) => { panictry!(p.bump()); token::NtLifetime(Box::new(sn)) } + _ => { + let token_str = pprust::token_to_string(&p.token); + panic!(p.fatal(&format!("expected life, found {}", + &token_str[..]))) + } + }, "path" => { token::NtPath(Box::new(panictry!(p.parse_path(LifetimeAndTypesWithoutColons)))) } @@ -547,7 +555,7 @@ pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal { _ => { panic!(p.span_fatal_help(sp, &format!("invalid fragment specifier `{}`", name), - "valid fragment specifiers are `ident`, `block`, \ + "valid fragment specifiers are `ident`, `life`, `block`, \ `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \ and `item`")) } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index febfc7a97fe3d..d071e1078e693 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -505,8 +505,8 @@ fn is_in_follow(_: &ExtCtxt, tok: &Token, frag: &str) -> Result { _ => Ok(false) } }, - "ident" => { - // being a single token, idents are harmless + "ident" | "life" => { + // being a single token, idents and lives are harmless Ok(true) }, "meta" | "tt" => { diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 368a9f0c27e56..355d29d550523 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -15,7 +15,7 @@ use codemap::{Span, DUMMY_SP}; use diagnostic::SpanHandler; use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; use parse::token::{Eof, DocComment, Interpolated, MatchNt, SubstNt}; -use parse::token::{Token, NtIdent, SpecialMacroVar}; +use parse::token::{Token, NtIdent, NtLifetime, SpecialMacroVar}; use parse::token; use parse::lexer::TokenAndSpan; @@ -299,6 +299,11 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { r.cur_tok = token::Ident(**sn, b); return ret_val; } + MatchedNonterminal(NtLifetime(ref sn)) => { + r.cur_span = sp; + r.cur_tok = token::Lifetime(**sn); + return ret_val; + } MatchedNonterminal(ref other_whole_nt) => { // FIXME(pcwalton): Bad copy. r.cur_span = sp; diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 4bf15f509a048..c1f18b14a5299 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -679,6 +679,8 @@ pub fn noop_fold_interpolated(nt: token::Nonterminal, fld: &mut T) token::NtTy(ty) => token::NtTy(fld.fold_ty(ty)), token::NtIdent(id, is_mod_name) => token::NtIdent(Box::new(fld.fold_ident(*id)), is_mod_name), + token::NtLifetime(id) => token::NtLifetime(Box::new( + fld.fold_lifetime(ast_util::name_to_dummy_lifetime(id.name)).name.ident())), token::NtMeta(meta_item) => token::NtMeta(fld.fold_meta_item(meta_item)), token::NtPath(path) => token::NtPath(Box::new(fld.fold_path(*path))), token::NtTT(tt) => token::NtTT(P(fld.fold_tt(&*tt))), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b3b20f2d0ae6f..939dd300b9f4b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -537,6 +537,9 @@ impl<'a> Parser<'a> { token::Interpolated(token::NtIdent(..)) => { self.bug("ident interpolation not converted to real token"); } + token::Interpolated(token::NtLifetime(..)) => { + self.bug("life interpolation not converted to real token"); + } _ => { let token_str = self.this_token_to_string(); Err(self.fatal(&format!("expected ident, found `{}`", diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 832fec40199b8..38ecffc81b0ae 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -377,6 +377,7 @@ pub enum Nonterminal { NtExpr(P), NtTy(P), NtIdent(Box, IdentStyle), + NtLifetime(Box), /// Stuff inside brackets for attributes NtMeta(P), NtPath(Box), @@ -399,6 +400,7 @@ impl fmt::Debug for Nonterminal { NtExpr(..) => f.pad("NtExpr(..)"), NtTy(..) => f.pad("NtTy(..)"), NtIdent(..) => f.pad("NtIdent(..)"), + NtLifetime(..) => f.pad("NtLifetime(..)"), NtMeta(..) => f.pad("NtMeta(..)"), NtPath(..) => f.pad("NtPath(..)"), NtTT(..) => f.pad("NtTT(..)"), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index b71d65a8fb0c5..60ff734b7dab0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -296,6 +296,8 @@ pub fn token_to_string(tok: &Token) -> String { token::NtStmt(ref e) => stmt_to_string(&**e), token::NtPat(ref e) => pat_to_string(&**e), token::NtIdent(ref e, _) => ident_to_string(&**e), + token::NtLifetime(ref e) => + lifetime_to_string(&ast_util::name_to_dummy_lifetime(e.name)), token::NtTT(ref e) => tt_to_string(&**e), token::NtArm(ref e) => arm_to_string(&*e), token::NtImplItem(ref e) => impl_item_to_string(&**e), diff --git a/src/test/run-pass/macro-interpolation.rs b/src/test/run-pass/macro-interpolation.rs index 6dcd1538ebce2..34c87a0da3dcc 100644 --- a/src/test/run-pass/macro-interpolation.rs +++ b/src/test/run-pass/macro-interpolation.rs @@ -10,8 +10,10 @@ macro_rules! overly_complicated { - ($fnname:ident, $arg:ident, $ty:ty, $body:block, $val:expr, $pat:pat, $res:path) => + ($fnname:ident, $arg:ident, $ty:ty, $body:block, $val:expr, $pat:pat, $res:path, + $label:life) => ({ + $label: loop { break $label; } fn $fnname($arg: $ty) -> Option<$ty> $body match $fnname($val) { Some($pat) => { @@ -25,6 +27,6 @@ macro_rules! overly_complicated { pub fn main() { assert!(overly_complicated!(f, x, Option, { return Some(x); }, - Some(8), Some(y), y) == 8) + Some(8), Some(y), y, 'test) == 8) }