Skip to content

Commit a81804b

Browse files
committed
syntax: Introduce a struct MacArgs for macro arguments
1 parent fdc0011 commit a81804b

File tree

19 files changed

+192
-112
lines changed

19 files changed

+192
-112
lines changed

src/librustc_lint/builtin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1453,7 +1453,7 @@ impl EarlyLintPass for KeywordIdents {
14531453
self.check_tokens(cx, mac_def.stream());
14541454
}
14551455
fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::Mac) {
1456-
self.check_tokens(cx, mac.tts.clone().into());
1456+
self.check_tokens(cx, mac.args.inner_tokens());
14571457
}
14581458
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: ast::Ident) {
14591459
self.check_ident_token(cx, UnderMacro(false), ident);

src/librustc_parse/parser/attr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ impl<'a> Parser<'a> {
244244
Ok(attrs)
245245
}
246246

247-
fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
247+
pub(super) fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
248248
let lit = self.parse_lit()?;
249249
debug!("checking if {:?} is unusuffixed", lit);
250250

src/librustc_parse/parser/expr.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -922,12 +922,11 @@ impl<'a> Parser<'a> {
922922
// `!`, as an operator, is prefix, so we know this isn't that.
923923
if self.eat(&token::Not) {
924924
// MACRO INVOCATION expression
925-
let (delim, tts) = self.expect_delimited_token_tree()?;
925+
let args = self.parse_mac_args()?;
926926
hi = self.prev_span;
927927
ex = ExprKind::Mac(Mac {
928928
path,
929-
tts,
930-
delim,
929+
args,
931930
span: lo.to(hi),
932931
prior_type_ascription: self.last_type_ascription,
933932
});

src/librustc_parse/parser/item.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use syntax::ast::{ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind, Us
88
use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness, Extern, StrLit};
99
use syntax::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind};
1010
use syntax::ast::{Ty, TyKind, Generics, TraitRef, EnumDef, Variant, VariantData, StructField};
11-
use syntax::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, FnSig, SelfKind, Param};
11+
use syntax::ast::{Mac, Block, BindingMode, FnDecl, FnSig, SelfKind, Param};
1212
use syntax::print::pprust;
1313
use syntax::ptr::P;
1414
use syntax::ThinVec;
@@ -437,16 +437,15 @@ impl<'a> Parser<'a> {
437437
// Item macro
438438
let path = self.parse_path(PathStyle::Mod)?;
439439
self.expect(&token::Not)?;
440-
let (delim, tts) = self.expect_delimited_token_tree()?;
441-
if delim != MacDelimiter::Brace && !self.eat(&token::Semi) {
440+
let args = self.parse_mac_args()?;
441+
if args.need_semicolon() && !self.eat(&token::Semi) {
442442
self.report_invalid_macro_expansion_item();
443443
}
444444

445445
let hi = self.prev_span;
446446
let mac = Mac {
447447
path,
448-
tts,
449-
delim,
448+
args,
450449
span: mac_lo.to(hi),
451450
prior_type_ascription: self.last_type_ascription,
452451
};
@@ -518,15 +517,14 @@ impl<'a> Parser<'a> {
518517
*at_end = true;
519518

520519
// eat a matched-delimiter token tree:
521-
let (delim, tts) = self.expect_delimited_token_tree()?;
522-
if delim != MacDelimiter::Brace {
520+
let args = self.parse_mac_args()?;
521+
if args.need_semicolon() {
523522
self.expect_semi()?;
524523
}
525524

526525
Ok(Some(Mac {
527526
path,
528-
tts,
529-
delim,
527+
args,
530528
span: lo.to(self.prev_span),
531529
prior_type_ascription: self.last_type_ascription,
532530
}))
@@ -1660,12 +1658,12 @@ impl<'a> Parser<'a> {
16601658
self.bump();
16611659

16621660
let ident = self.parse_ident()?;
1663-
let (delim, tokens) = self.expect_delimited_token_tree()?;
1664-
if delim != MacDelimiter::Brace && !self.eat(&token::Semi) {
1661+
let args = self.parse_mac_args()?;
1662+
if args.need_semicolon() && !self.eat(&token::Semi) {
16651663
self.report_invalid_macro_expansion_item();
16661664
}
16671665

1668-
(ident, ast::MacroDef { tokens, legacy: true })
1666+
(ident, ast::MacroDef { tokens: args.inner_tokens(), legacy: true })
16691667
} else {
16701668
return Ok(None);
16711669
};

src/librustc_parse/parser/mod.rs

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::lexer::UnmatchedBrace;
1616

1717
use syntax::ast::{
1818
self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Extern, Ident, StrLit,
19-
IsAsync, MacDelimiter, Mutability, Visibility, VisibilityKind, Unsafety,
19+
IsAsync, MacArgs, MacDelimiter, Mutability, Visibility, VisibilityKind, Unsafety,
2020
};
2121

2222
use syntax::print::pprust;
@@ -1010,27 +1010,49 @@ impl<'a> Parser<'a> {
10101010
}
10111011
}
10121012

1013-
fn expect_delimited_token_tree(&mut self) -> PResult<'a, (MacDelimiter, TokenStream)> {
1014-
let delim = match self.token.kind {
1015-
token::OpenDelim(delim) => delim,
1016-
_ => {
1017-
let msg = "expected open delimiter";
1018-
let mut err = self.fatal(msg);
1019-
err.span_label(self.token.span, msg);
1020-
return Err(err)
1013+
fn parse_mac_args(&mut self) -> PResult<'a, P<MacArgs>> {
1014+
self.parse_mac_args_common(true)
1015+
}
1016+
1017+
#[allow(dead_code)]
1018+
fn parse_attr_args(&mut self) -> PResult<'a, P<MacArgs>> {
1019+
self.parse_mac_args_common(false)
1020+
}
1021+
1022+
fn parse_mac_args_common(&mut self, delimited_only: bool) -> PResult<'a, P<MacArgs>> {
1023+
Ok(P(if self.check(&token::OpenDelim(DelimToken::Paren)) ||
1024+
self.check(&token::OpenDelim(DelimToken::Bracket)) ||
1025+
self.check(&token::OpenDelim(DelimToken::Brace)) {
1026+
match self.parse_token_tree() {
1027+
TokenTree::Delimited(dspan, delim, tokens) =>
1028+
MacArgs::Delimited(dspan, MacDelimiter::from_token(delim), tokens),
1029+
_ => unreachable!(),
10211030
}
1022-
};
1023-
let tts = match self.parse_token_tree() {
1024-
TokenTree::Delimited(_, _, tts) => tts,
1025-
_ => unreachable!(),
1026-
};
1027-
let delim = match delim {
1028-
token::Paren => MacDelimiter::Parenthesis,
1029-
token::Bracket => MacDelimiter::Bracket,
1030-
token::Brace => MacDelimiter::Brace,
1031-
token::NoDelim => self.bug("unexpected no delimiter"),
1032-
};
1033-
Ok((delim, tts.into()))
1031+
} else if !delimited_only {
1032+
if self.eat(&token::Eq) {
1033+
let eq_span = self.prev_span;
1034+
let mut is_interpolated_expr = false;
1035+
if let token::Interpolated(nt) = &self.token.kind {
1036+
if let token::NtExpr(..) = **nt {
1037+
is_interpolated_expr = true;
1038+
}
1039+
}
1040+
let token_tree = if is_interpolated_expr {
1041+
// We need to accept arbitrary interpolated expressions to continue
1042+
// supporting things like `doc = $expr` that work on stable.
1043+
// Non-literal interpolated expressions are rejected after expansion.
1044+
self.parse_token_tree()
1045+
} else {
1046+
self.parse_unsuffixed_lit()?.token_tree()
1047+
};
1048+
1049+
MacArgs::Eq(eq_span, token_tree.into())
1050+
} else {
1051+
MacArgs::Empty
1052+
}
1053+
} else {
1054+
return self.unexpected();
1055+
}))
10341056
}
10351057

10361058
fn parse_or_use_outer_attributes(

src/librustc_parse/parser/pat.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -595,11 +595,10 @@ impl<'a> Parser<'a> {
595595
/// Parse macro invocation
596596
fn parse_pat_mac_invoc(&mut self, lo: Span, path: Path) -> PResult<'a, PatKind> {
597597
self.bump();
598-
let (delim, tts) = self.expect_delimited_token_tree()?;
598+
let args = self.parse_mac_args()?;
599599
let mac = Mac {
600600
path,
601-
tts,
602-
delim,
601+
args,
603602
span: lo.to(self.prev_span),
604603
prior_type_ascription: self.last_type_ascription,
605604
};

src/librustc_parse/parser/stmt.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use syntax::ThinVec;
1010
use syntax::ptr::P;
1111
use syntax::ast;
1212
use syntax::ast::{DUMMY_NODE_ID, Stmt, StmtKind, Local, Block, BlockCheckMode, Expr, ExprKind};
13-
use syntax::ast::{Attribute, AttrStyle, VisibilityKind, MacStmtStyle, Mac, MacDelimiter};
13+
use syntax::ast::{Attribute, AttrStyle, VisibilityKind, MacStmtStyle, Mac};
1414
use syntax::util::classify;
1515
use syntax::token;
1616
use syntax::source_map::{respan, Span};
@@ -93,23 +93,23 @@ impl<'a> Parser<'a> {
9393
}));
9494
}
9595

96-
let (delim, tts) = self.expect_delimited_token_tree()?;
96+
let args = self.parse_mac_args()?;
97+
let delim = args.delim();
9798
let hi = self.prev_span;
9899

99-
let style = if delim == MacDelimiter::Brace {
100+
let style = if delim == token::Brace {
100101
MacStmtStyle::Braces
101102
} else {
102103
MacStmtStyle::NoBraces
103104
};
104105

105106
let mac = Mac {
106107
path,
107-
tts,
108-
delim,
108+
args,
109109
span: lo.to(hi),
110110
prior_type_ascription: self.last_type_ascription,
111111
};
112-
let kind = if delim == MacDelimiter::Brace ||
112+
let kind = if delim == token::Brace ||
113113
self.token == token::Semi || self.token == token::Eof {
114114
StmtKind::Mac(P((mac, style, attrs.into())))
115115
}

src/librustc_parse/parser/ty.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,10 @@ impl<'a> Parser<'a> {
177177
let path = self.parse_path(PathStyle::Type)?;
178178
if self.eat(&token::Not) {
179179
// Macro invocation in type position
180-
let (delim, tts) = self.expect_delimited_token_tree()?;
180+
let args = self.parse_mac_args()?;
181181
let mac = Mac {
182182
path,
183-
tts,
184-
delim,
183+
args,
185184
span: lo.to(self.prev_span),
186185
prior_type_ascription: self.last_type_ascription,
187186
};

src/libsyntax/ast.rs

Lines changed: 69 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub use syntax_pos::symbol::{Ident, Symbol as Name};
2727
use crate::ptr::P;
2828
use crate::source_map::{dummy_spanned, respan, Spanned};
2929
use crate::token::{self, DelimToken};
30-
use crate::tokenstream::TokenStream;
30+
use crate::tokenstream::{TokenStream, TokenTree, DelimSpan};
3131

3232
use syntax_pos::symbol::{kw, sym, Symbol};
3333
use syntax_pos::{Span, DUMMY_SP, ExpnId};
@@ -40,6 +40,7 @@ use rustc_index::vec::Idx;
4040
use rustc_serialize::{self, Decoder, Encoder};
4141
use rustc_macros::HashStable_Generic;
4242

43+
use std::iter;
4344
use std::fmt;
4445

4546
#[cfg(test)]
@@ -1372,34 +1373,78 @@ pub enum Movability {
13721373
Movable,
13731374
}
13741375

1375-
/// Represents a macro invocation. The `Path` indicates which macro
1376-
/// is being invoked, and the vector of token-trees contains the source
1377-
/// of the macro invocation.
1378-
///
1379-
/// N.B., the additional ident for a `macro_rules`-style macro is actually
1380-
/// stored in the enclosing item.
1376+
/// Represents a macro invocation. The `path` indicates which macro
1377+
/// is being invoked, and the `args` are arguments passed to it.
13811378
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
13821379
pub struct Mac {
13831380
pub path: Path,
1384-
pub delim: MacDelimiter,
1385-
pub tts: TokenStream,
1381+
pub args: P<MacArgs>,
13861382
pub span: Span,
13871383
pub prior_type_ascription: Option<(Span, bool)>,
13881384
}
13891385

1390-
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
1391-
pub enum MacDelimiter {
1392-
Parenthesis,
1393-
Bracket,
1394-
Brace,
1386+
/// Arguments passed to an attribute or a function-like macro.
1387+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1388+
pub enum MacArgs {
1389+
/// No arguments - `#[attr]`.
1390+
Empty,
1391+
/// Delimited arguments - `#[attr()/[]/{}]` or `mac!()/[]/{}`.
1392+
Delimited(DelimSpan, MacDelimiter, TokenStream),
1393+
/// Arguments of a key-value attribute - `#[attr = "value"]`.
1394+
/// Span belongs to the `=` token, token stream is the "value".
1395+
Eq(Span, TokenStream),
1396+
}
1397+
1398+
impl MacArgs {
1399+
pub fn delim(&self) -> DelimToken {
1400+
match self {
1401+
MacArgs::Delimited(_, delim, _) => delim.to_token(),
1402+
MacArgs::Empty | MacArgs::Eq(..) => token::NoDelim,
1403+
}
1404+
}
1405+
1406+
/// Tokens inside the delimiters or after `=`.
1407+
/// Proc macros see these tokens, for example.
1408+
pub fn inner_tokens(&self) -> TokenStream {
1409+
match self {
1410+
MacArgs::Empty => TokenStream::default(),
1411+
MacArgs::Delimited(.., tokens) => tokens.clone(),
1412+
MacArgs::Eq(.., tokens) => tokens.clone(),
1413+
}
1414+
}
1415+
1416+
/// Tokens together with the delimiters or `=`.
1417+
/// Use of this functions generally means that something suspicious or hacky is happening.
1418+
pub fn outer_tokens(&self) -> TokenStream {
1419+
match *self {
1420+
MacArgs::Empty => TokenStream::default(),
1421+
MacArgs::Delimited(dspan, delim, ref tokens) =>
1422+
TokenTree::Delimited(dspan, delim.to_token(), tokens.clone()).into(),
1423+
MacArgs::Eq(eq_span, ref tokens) => iter::once(TokenTree::token(token::Eq, eq_span))
1424+
.chain(tokens.trees()).collect(),
1425+
}
1426+
}
1427+
1428+
/// Whether a macro with these arguments needs a semicolon
1429+
/// when used as a standalone item or statement.
1430+
pub fn need_semicolon(&self) -> bool {
1431+
!matches!(self, MacArgs::Delimited(_, MacDelimiter::Brace ,_))
1432+
}
13951433
}
13961434

13971435
impl Mac {
13981436
pub fn stream(&self) -> TokenStream {
1399-
self.tts.clone()
1437+
self.args.inner_tokens()
14001438
}
14011439
}
14021440

1441+
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
1442+
pub enum MacDelimiter {
1443+
Parenthesis,
1444+
Bracket,
1445+
Brace,
1446+
}
1447+
14031448
impl MacDelimiter {
14041449
crate fn to_token(self) -> DelimToken {
14051450
match self {
@@ -1408,6 +1453,15 @@ impl MacDelimiter {
14081453
MacDelimiter::Brace => DelimToken::Brace,
14091454
}
14101455
}
1456+
1457+
pub fn from_token(delim: DelimToken) -> MacDelimiter {
1458+
match delim {
1459+
token::Paren => MacDelimiter::Parenthesis,
1460+
token::Bracket => MacDelimiter::Bracket,
1461+
token::Brace => MacDelimiter::Brace,
1462+
token::NoDelim => panic!("expected a delimiter"),
1463+
}
1464+
}
14111465
}
14121466

14131467
/// Represents a macro definition.

src/libsyntax/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#![feature(const_transmute)]
1313
#![feature(crate_visibility_modifier)]
1414
#![feature(label_break_value)]
15+
#![feature(matches_macro)]
1516
#![feature(nll)]
1617
#![feature(try_trait)]
1718
#![feature(slice_patterns)]

0 commit comments

Comments
 (0)