diff options
| author | Dan Aloni <alonid@gmail.com> | 2018-04-10 02:08:47 +0300 |
|---|---|---|
| committer | Dan Aloni <alonid@gmail.com> | 2018-05-13 19:17:02 +0300 |
| commit | 37ed2ab91038567bafe3fd2e545c7d1631ff2ab0 (patch) | |
| tree | 27b8125e37ecd34720f6cee3286e821c6a6df96d /src/libsyntax/ext | |
| parent | 3e955a058108fcadf0a8222de5868b0c905534d5 (diff) | |
| download | rust-37ed2ab91038567bafe3fd2e545c7d1631ff2ab0.tar.gz rust-37ed2ab91038567bafe3fd2e545c7d1631ff2ab0.zip | |
Macros: Add a 'literal' fragment specifier
Implements RFC 1576.
See: https://github.com/rust-lang/rfcs/blob/master/text/1576-macros-literal-matcher.md
Changes are mostly in libsyntax, docs, and tests. Feature gate is
enabled for 1.27.0.
Many thanks to Vadim Petrochenkov for following through code reviews
and suggestions.
Example:
````rust
macro_rules! test_literal {
($l:literal) => {
println!("literal: {}", $l);
};
($e:expr) => {
println!("expr: {}", $e);
};
}
fn main() {
let a = 1;
test_literal!(a);
test_literal!(2);
test_literal!(-3);
}
```
Output:
```
expr: 1
literal: 2
literal: -3
```
Diffstat (limited to 'src/libsyntax/ext')
| -rw-r--r-- | src/libsyntax/ext/tt/macro_parser.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/ext/tt/macro_rules.rs | 21 |
2 files changed, 21 insertions, 2 deletions
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 71634ada894..f0339b89839 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -735,6 +735,7 @@ fn may_begin_with(name: &str, token: &Token) -> bool { "expr" => token.can_begin_expr(), "ty" => token.can_begin_type(), "ident" => get_macro_ident(token).is_some(), + "literal" => token.can_begin_literal_or_bool(), "vis" => match *token { // The follow-set of :vis + "priv" keyword + interpolated Token::Comma | Token::Ident(..) | Token::Interpolated(_) => true, @@ -821,6 +822,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { }, "pat" => token::NtPat(panictry!(p.parse_pat())), "expr" => token::NtExpr(panictry!(p.parse_expr())), + "literal" => token::NtLiteral(panictry!(p.parse_literal_maybe_minus())), "ty" => token::NtTy(panictry!(p.parse_ty())), // this could be handled like a token, since it is one "ident" => if let Some((ident, is_raw)) = get_macro_ident(&p.token) { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index ffe68289d52..1fc5aed7e7a 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -647,7 +647,7 @@ fn check_matcher_core(sess: &ParseSess, let msg = format!("invalid fragment specifier `{}`", bad_frag); sess.span_diagnostic.struct_span_err(token.span(), &msg) .help("valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, \ - `pat`, `ty`, `path`, `meta`, `tt`, `item` and `vis`") + `pat`, `ty`, `literal`, `path`, `meta`, `tt`, `item` and `vis`") .emit(); // (This eliminates false positives and duplicates // from error messages.) @@ -784,6 +784,7 @@ fn frag_can_be_followed_by_any(frag: &str) -> bool { "item" | // always terminated by `}` or `;` "block" | // exactly one token tree "ident" | // exactly one token tree + "literal" | // exactly one token tree "meta" | // exactly one token tree "lifetime" | // exactly one token tree "tt" => // exactly one token tree @@ -850,6 +851,10 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result<bool, (String, &' // being a single token, idents and lifetimes are harmless Ok(true) }, + "literal" => { + // literals may be of a single token, or two tokens (negative numbers) + Ok(true) + }, "meta" | "tt" => { // being either a single token or a delimited sequence, tt is // harmless @@ -873,7 +878,7 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result<bool, (String, &' _ => Err((format!("invalid fragment specifier `{}`", frag), "valid fragment specifiers are `ident`, `block`, \ `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt`, \ - `item` and `vis`")) + `literal`, `item` and `vis`")) } } } @@ -913,6 +918,18 @@ fn is_legal_fragment_specifier(sess: &ParseSess, } true }, + "literal" => { + if !features.macro_literal_matcher && + !attr::contains_name(attrs, "allow_internal_unstable") { + let explain = feature_gate::EXPLAIN_LITERAL_MATCHER; + emit_feature_err(sess, + "macro_literal_matcher", + frag_span, + GateIssue::Language, + explain); + } + true + }, "vis" => { if !features.macro_vis_matcher && !attr::contains_name(attrs, "allow_internal_unstable") { |
