Skip to content

Commit fa0b944

Browse files
committed
Add str matcher for macros which matches string literals
1 parent 875ec8d commit fa0b944

File tree

4 files changed

+43
-4
lines changed

4 files changed

+43
-4
lines changed

src/libsyntax/ext/tt/macro_parser.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,7 @@ fn may_begin_with(name: &str, token: &Token) -> bool {
509509
}
510510

511511
match name {
512+
"str" => token.can_begin_str(),
512513
"expr" => token.can_begin_expr(),
513514
"ty" => token.can_begin_type(),
514515
"ident" => token.is_ident(),
@@ -585,7 +586,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
585586
}
586587
},
587588
"pat" => token::NtPat(panictry!(p.parse_pat())),
588-
"expr" => token::NtExpr(panictry!(p.parse_expr())),
589+
"expr" | "str" => token::NtExpr(panictry!(p.parse_expr())),
589590
"ty" => token::NtTy(panictry!(p.parse_ty())),
590591
// this could be handled like a token, since it is one
591592
"ident" => match p.token {

src/libsyntax/ext/tt/macro_rules.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ fn check_matcher_core(sess: &ParseSess,
634634
let msg = format!("invalid fragment specifier `{}`", bad_frag);
635635
sess.span_diagnostic.struct_span_err(token.span(), &msg)
636636
.help("valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, \
637-
`pat`, `ty`, `path`, `meta`, `tt`, `item` and `vis`")
637+
`pat`, `ty`, `path`, `meta`, `tt`, `item`, `str` and `vis`")
638638
.emit();
639639
// (This eliminates false positives and duplicates
640640
// from error messages.)
@@ -807,7 +807,7 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> Result<bool, (String, &'
807807
// maintain
808808
Ok(true)
809809
},
810-
"stmt" | "expr" => match *tok {
810+
"stmt" | "expr" | "str" => match *tok {
811811
TokenTree::Token(_, ref tok) => match *tok {
812812
FatArrow | Comma | Semi => Ok(true),
813813
_ => Ok(false)
@@ -859,7 +859,7 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> Result<bool, (String, &'
859859
_ => Err((format!("invalid fragment specifier `{}`", frag),
860860
"valid fragment specifiers are `ident`, `block`, \
861861
`stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt`, \
862-
`item` and `vis`"))
862+
`item`, `str` and `vis`"))
863863
}
864864
}
865865
}
@@ -899,6 +899,18 @@ fn is_legal_fragment_specifier(sess: &ParseSess,
899899
}
900900
true
901901
},
902+
"str" => {
903+
if !features.borrow().macro_str_matcher
904+
&& !attr::contains_name(attrs, "allow_internal_unstable") {
905+
let explain = feature_gate::EXPLAIN_STR_MATCHER;
906+
emit_feature_err(sess,
907+
"macro_str_matcher",
908+
frag_span,
909+
GateIssue::Language,
910+
explain);
911+
}
912+
true
913+
},
902914
_ => false,
903915
}
904916
}

src/libsyntax/feature_gate.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,9 @@ declare_features! (
405405
// `crate` as visibility modifier, synonymous to `pub(crate)`
406406
(active, crate_visibility_modifier, "1.23.0", Some(45388)),
407407

408+
// Allows use of the :str macro fragment specifier
409+
(active, macro_str_matcher, "1.23.0", None),
410+
408411
// extern types
409412
(active, extern_types, "1.23.0", Some(43467)),
410413
);
@@ -1158,6 +1161,9 @@ pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
11581161
pub const EXPLAIN_VIS_MATCHER: &'static str =
11591162
":vis fragment specifier is experimental and subject to change";
11601163

1164+
pub const EXPLAIN_STR_MATCHER: &'static str =
1165+
":str fragment specifier is experimental and subject to change";
1166+
11611167
pub const EXPLAIN_PLACEMENT_IN: &'static str =
11621168
"placement-in expression syntax is experimental and subject to change.";
11631169

src/libsyntax/parse/token.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,26 @@ impl Token {
210210
}
211211
}
212212

213+
/// Returns `true` if the token can appear at the start of an string literal.
214+
pub fn can_begin_str(&self) -> bool {
215+
match *self {
216+
Literal(Str_(..), _) |
217+
Literal(StrRaw(..), _) => true,
218+
Interpolated(ref nt) => {
219+
if let NtExpr(ref e) = nt.0 {
220+
if let ast::ExprKind::Lit(ref lit) = e.node {
221+
if let ast::LitKind::Str(..) = lit.node {
222+
return true;
223+
}
224+
}
225+
}
226+
227+
false
228+
},
229+
_ => false,
230+
}
231+
}
232+
213233
/// Returns `true` if the token can appear at the start of an expression.
214234
pub fn can_begin_expr(&self) -> bool {
215235
match *self {

0 commit comments

Comments
 (0)