Skip to content

Commit 4163a72

Browse files
committed
Add a special macro nonterminal $crate
I will document this in the macros guide, after the conflicting rust-lang#16995 lands.
1 parent 9d5ebd5 commit 4163a72

File tree

13 files changed

+138
-12
lines changed

13 files changed

+138
-12
lines changed

src/libsyntax/ast.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,11 @@ pub enum TokenTree {
594594
TTSeq(Span, Rc<Vec<TokenTree>>, Option<::parse::token::Token>, bool),
595595

596596
/// A syntactic variable that will be filled in by macro expansion.
597-
TTNonterminal(Span, Ident)
597+
TTNonterminal(Span, Ident),
598+
599+
/// A syntactic variable that will be filled in with the name of
600+
/// the crate a macro was imported from, if any.
601+
TTCrateNonterminal(Span),
598602
}
599603

600604
// Matchers are nodes defined-by and recognized-by the main rust parser and

src/libsyntax/ext/expand.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ pub fn expand_item(it: P<ast::Item>, fld: &mut MacroExpander)
279279
}
280280

281281
let mut new_items = match it.node {
282-
ast::ItemMac(..) => expand_item_mac(it, fld),
282+
ast::ItemMac(..) => expand_item_mac(it, None, fld),
283283
ast::ItemMod(_) | ast::ItemForeignMod(_) => {
284284
fld.cx.mod_push(it.ident);
285285
let macro_escape = contains_macro_escape(new_attrs.as_slice());
@@ -369,8 +369,9 @@ fn contains_macro_escape(attrs: &[ast::Attribute]) -> bool {
369369

370370
// Support for item-position macro invocations, exactly the same
371371
// logic as for expression-position macro invocations.
372-
pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
373-
-> SmallVector<P<ast::Item>> {
372+
pub fn expand_item_mac(it: P<ast::Item>,
373+
imported_from: Option<ast::Ident>,
374+
fld: &mut MacroExpander) -> SmallVector<P<ast::Item>> {
374375
let (extname, path_span, tts) = match it.node {
375376
ItemMac(codemap::Spanned {
376377
node: MacInvocTT(ref pth, ref tts, _),
@@ -450,7 +451,8 @@ pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
450451
});
451452
// DON'T mark before expansion.
452453
let MacroDef { name, ext }
453-
= macro_rules::add_new_extension(fld.cx, it.span, it.ident, tts);
454+
= macro_rules::add_new_extension(fld.cx, it.span, it.ident,
455+
imported_from, tts);
454456

455457
fld.cx.syntax_env.insert(intern(name.as_slice()), ext);
456458
if attr::contains_name(it.attrs.as_slice(), "macro_export") {
@@ -994,7 +996,7 @@ pub fn expand_crate(parse_sess: &parse::ParseSess,
994996
expander.cx.cfg(),
995997
expander.cx.parse_sess())
996998
.expect("expected a serialized item");
997-
expand_item_mac(item, &mut expander);
999+
expand_item_mac(item, Some(crate_name), &mut expander);
9981000
}
9991001
}
10001002

src/libsyntax/ext/quote.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,9 @@ fn mk_tt(cx: &ExtCtxt, sp: Span, tt: &ast::TokenTree) -> Vec<P<ast::Stmt>> {
674674

675675
vec!(cx.stmt_expr(e_push))
676676
}
677+
678+
ast::TTCrateNonterminal(sp)
679+
=> cx.span_fatal(sp, "can't use $crate in procedural quotes"),
677680
}
678681
}
679682

src/libsyntax/ext/tt/macro_rules.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ impl<'a> MacResult for ParserAnyMacro<'a> {
107107

108108
struct MacroRulesMacroExpander {
109109
name: Ident,
110+
imported_from: Option<Ident>,
110111
lhses: Vec<Rc<NamedMatch>>,
111112
rhses: Vec<Rc<NamedMatch>>,
112113
}
@@ -120,6 +121,7 @@ impl TTMacroExpander for MacroRulesMacroExpander {
120121
generic_extension(cx,
121122
sp,
122123
self.name,
124+
self.imported_from,
123125
arg,
124126
self.lhses.as_slice(),
125127
self.rhses.as_slice())
@@ -130,6 +132,7 @@ impl TTMacroExpander for MacroRulesMacroExpander {
130132
fn generic_extension<'cx>(cx: &'cx ExtCtxt,
131133
sp: Span,
132134
name: Ident,
135+
imported_from: Option<Ident>,
133136
arg: &[ast::TokenTree],
134137
lhses: &[Rc<NamedMatch>],
135138
rhses: &[Rc<NamedMatch>])
@@ -153,6 +156,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
153156
MatchedNonterminal(NtMatchers(ref mtcs)) => {
154157
// `None` is because we're not interpolating
155158
let arg_rdr = new_tt_reader(&cx.parse_sess().span_diagnostic,
159+
None,
156160
None,
157161
arg.iter()
158162
.map(|x| (*x).clone())
@@ -179,6 +183,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
179183
// rhs has holes ( `$id` and `$(...)` that need filled)
180184
let trncbr = new_tt_reader(&cx.parse_sess().span_diagnostic,
181185
Some(named_matches),
186+
imported_from,
182187
rhs);
183188
let p = Parser::new(cx.parse_sess(), cx.cfg(), box trncbr);
184189
// Let the context choose how to interpret the result.
@@ -205,6 +210,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
205210
pub fn add_new_extension(cx: &mut ExtCtxt,
206211
sp: Span,
207212
name: Ident,
213+
imported_from: Option<Ident>,
208214
arg: Vec<ast::TokenTree>) -> MacroDef {
209215
// these spans won't matter, anyways
210216
fn ms(m: Matcher_) -> Matcher {
@@ -233,6 +239,7 @@ pub fn add_new_extension(cx: &mut ExtCtxt,
233239

234240
// Parse the macro_rules! invocation (`none` is for no interpolations):
235241
let arg_reader = new_tt_reader(&cx.parse_sess().span_diagnostic,
242+
None,
236243
None,
237244
arg.clone());
238245
let argument_map = parse_or_else(cx.parse_sess(),
@@ -253,6 +260,7 @@ pub fn add_new_extension(cx: &mut ExtCtxt,
253260

254261
let exp = box MacroRulesMacroExpander {
255262
name: name,
263+
imported_from: imported_from,
256264
lhses: lhses,
257265
rhses: rhses,
258266
};

src/libsyntax/ext/tt/transcribe.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
// except according to those terms.
1010

1111
use ast;
12-
use ast::{TokenTree, TTDelim, TTTok, TTSeq, TTNonterminal, Ident};
12+
use ast::{TokenTree, TTDelim, TTTok, TTSeq, TTNonterminal, TTCrateNonterminal, Ident};
1313
use codemap::{Span, DUMMY_SP};
1414
use diagnostic::SpanHandler;
1515
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
16-
use parse::token::{EOF, INTERPOLATED, IDENT, Token, NtIdent};
16+
use parse::token::{EOF, INTERPOLATED, IDENT, MOD_SEP, Token, NtIdent};
1717
use parse::token;
1818
use parse::lexer::TokenAndSpan;
1919

@@ -36,6 +36,10 @@ pub struct TtReader<'a> {
3636
stack: Vec<TtFrame>,
3737
/* for MBE-style macro transcription */
3838
interpolations: HashMap<Ident, Rc<NamedMatch>>,
39+
imported_from: Option<Ident>,
40+
41+
// Some => return imported_from as the next token
42+
crate_name_next: Option<Span>,
3943
repeat_idx: Vec<uint>,
4044
repeat_len: Vec<uint>,
4145
/* cached: */
@@ -48,6 +52,7 @@ pub struct TtReader<'a> {
4852
/// should) be none.
4953
pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler,
5054
interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
55+
imported_from: Option<Ident>,
5156
src: Vec<ast::TokenTree> )
5257
-> TtReader<'a> {
5358
let mut r = TtReader {
@@ -62,6 +67,8 @@ pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler,
6267
None => HashMap::new(),
6368
Some(x) => x,
6469
},
70+
imported_from: imported_from,
71+
crate_name_next: None,
6572
repeat_idx: Vec::new(),
6673
repeat_len: Vec::new(),
6774
/* dummy values, never read: */
@@ -130,7 +137,7 @@ fn lockstep_iter_size(t: &TokenTree, r: &TtReader) -> LockstepIterSize {
130137
lis_merge(lis, lockstep_iter_size(tt, r))
131138
})
132139
}
133-
TTTok(..) => LisUnconstrained,
140+
TTTok(..) | TTCrateNonterminal(..) => LisUnconstrained,
134141
TTNonterminal(_, name) => match *lookup_cur_matched(r, name) {
135142
MatchedNonterminal(_) => LisUnconstrained,
136143
MatchedSeq(ref ads, _) => LisConstraint(ads.len(), name)
@@ -147,6 +154,14 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
147154
sp: r.cur_span.clone(),
148155
};
149156
loop {
157+
match r.crate_name_next.take() {
158+
None => (),
159+
Some(sp) => {
160+
r.cur_span = sp;
161+
r.cur_tok = IDENT(r.imported_from.unwrap(), true);
162+
return ret_val;
163+
},
164+
}
150165
let should_pop = match r.stack.last() {
151166
None => {
152167
assert_eq!(ret_val.tok, EOF);
@@ -274,6 +289,18 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
274289
}
275290
}
276291
}
292+
TTCrateNonterminal(sp) => {
293+
r.stack.mut_last().unwrap().idx += 1;
294+
295+
if r.imported_from.is_some() {
296+
r.cur_span = sp;
297+
r.cur_tok = MOD_SEP;
298+
r.crate_name_next = Some(sp);
299+
return ret_val;
300+
}
301+
302+
// otherwise emit nothing and proceed to the next token
303+
}
277304
}
278305
}
279306
}

src/libsyntax/fold.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,8 @@ pub fn noop_fold_tt<T: Folder>(tt: &TokenTree, fld: &mut T) -> TokenTree {
563563
sep.clone().map(|tok| fld.fold_token(tok)),
564564
is_optional),
565565
TTNonterminal(sp,ref ident) =>
566-
TTNonterminal(sp,fld.fold_ident(*ident))
566+
TTNonterminal(sp,fld.fold_ident(*ident)),
567+
TTCrateNonterminal(sp) => TTCrateNonterminal(sp),
567568
}
568569
}
569570

src/libsyntax/parse/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>)
271271
pub fn tts_to_parser<'a>(sess: &'a ParseSess,
272272
tts: Vec<ast::TokenTree>,
273273
cfg: ast::CrateConfig) -> Parser<'a> {
274-
let trdr = lexer::new_tt_reader(&sess.span_diagnostic, None, tts);
274+
let trdr = lexer::new_tt_reader(&sess.span_diagnostic, None, None, tts);
275275
Parser::new(sess, cfg, box trdr)
276276
}
277277

src/libsyntax/parse/parser.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ use ast::{StructVariantKind, BiSub};
4949
use ast::StrStyle;
5050
use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfValue};
5151
use ast::{TokenTree, TraitItem, TraitRef, TTDelim, TTSeq, TTTok};
52-
use ast::{TTNonterminal, TupleVariantKind, Ty, Ty_, TyBot, TyBox};
52+
use ast::{TTNonterminal, TTCrateNonterminal, TupleVariantKind, Ty, Ty_, TyBot, TyBox};
5353
use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn};
5454
use ast::{TyTypeof, TyInfer, TypeMethod};
5555
use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyRptr};
@@ -2436,6 +2436,9 @@ impl<'a> Parser<'a> {
24362436
Spanned { node, .. } => node,
24372437
};
24382438
TTSeq(mk_sp(sp.lo, p.span.hi), Rc::new(seq), s, z)
2439+
} else if token::is_keyword_allow_following_colon(keywords::Crate, &p.token) {
2440+
p.bump();
2441+
TTCrateNonterminal(sp)
24392442
} else {
24402443
TTNonterminal(sp, p.parse_ident())
24412444
}

src/libsyntax/parse/token.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,13 @@ pub fn is_keyword(kw: keywords::Keyword, tok: &Token) -> bool {
706706
}
707707
}
708708

709+
pub fn is_keyword_allow_following_colon(kw: keywords::Keyword, tok: &Token) -> bool {
710+
match *tok {
711+
token::IDENT(sid, _) => { kw.to_name() == sid.name }
712+
_ => { false }
713+
}
714+
}
715+
709716
pub fn is_any_keyword(tok: &Token) -> bool {
710717
match *tok {
711718
token::IDENT(sid, false) => {

src/libsyntax/print/pprust.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,9 @@ impl<'a> State<'a> {
10071007
try!(word(&mut self.s, "$"));
10081008
self.print_ident(name)
10091009
}
1010+
ast::TTCrateNonterminal(_) => {
1011+
word(&mut self.s, "$crate")
1012+
}
10101013
}
10111014
}
10121015

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(macro_rules)]
12+
13+
pub fn increment(x: uint) -> uint {
14+
x + 1
15+
}
16+
17+
#[macro_export]
18+
macro_rules! increment (
19+
($x:expr) => ($crate::increment($x))
20+
)
21+
22+
pub fn check_local() {
23+
assert_eq!(increment!(3), 4);
24+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// aux-build:macro_crate_nonterminal.rs
12+
// ignore-stage1
13+
14+
#![feature(phase)]
15+
16+
#[phase(plugin, link)]
17+
extern crate "macro_crate_nonterminal" as new_name;
18+
19+
pub fn main() {
20+
new_name::check_local();
21+
assert_eq!(increment!(5), 6);
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// aux-build:macro_crate_nonterminal.rs
12+
// ignore-stage1
13+
14+
#![feature(phase)]
15+
16+
#[phase(plugin, link)]
17+
extern crate macro_crate_nonterminal;
18+
19+
pub fn main() {
20+
macro_crate_nonterminal::check_local();
21+
assert_eq!(increment!(5), 6);
22+
}

0 commit comments

Comments
 (0)