Skip to content

Commit ad7c647

Browse files
author
Keegan McAllister
committed
Add a special macro nonterminal $crate
1 parent 5e5924b commit ad7c647

File tree

12 files changed

+153
-9
lines changed

12 files changed

+153
-9
lines changed

src/librustdoc/html/highlight.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ fn doit(sess: &parse::ParseSess, mut lexer: lexer::StringReader,
166166
}
167167
}
168168

169+
// Special macro vars are like keywords
170+
token::SpecialVarNt(_) => "kw-2",
171+
169172
token::Lifetime(..) => "lifetime",
170173
token::DocComment(..) => "doccomment",
171174
token::Underscore | token::Eof | token::Interpolated(..) |

src/libsyntax/ast.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,7 @@ impl TokenTree {
884884
match *self {
885885
TtToken(_, token::DocComment(_)) => 2,
886886
TtToken(_, token::SubstNt(..)) => 2,
887+
TtToken(_, token::SpecialVarNt(..)) => 2,
887888
TtToken(_, token::MatchNt(..)) => 3,
888889
TtDelimited(_, ref delimed) => {
889890
delimed.tts.len() + 2
@@ -925,6 +926,12 @@ impl TokenTree {
925926
TtToken(sp, token::Ident(name, name_st))];
926927
v[index]
927928
}
929+
(&TtToken(sp, token::SpecialVarNt(var)), _) => {
930+
let v = [TtToken(sp, token::Dollar),
931+
TtToken(sp, token::Ident(token::str_to_ident(var.as_str()),
932+
token::Plain))];
933+
v[index]
934+
}
928935
(&TtToken(sp, token::MatchNt(name, kind, name_st, kind_st)), _) => {
929936
let v = [TtToken(sp, token::SubstNt(name, name_st)),
930937
TtToken(sp, token::Colon),

src/libsyntax/ext/expand.rs

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

434434
let mut new_items = match it.node {
435-
ast::ItemMac(..) => expand_item_mac(it, fld),
435+
ast::ItemMac(..) => expand_item_mac(it, None, fld),
436436
ast::ItemMod(_) | ast::ItemForeignMod(_) => {
437437
let valid_ident =
438438
it.ident.name != parse::token::special_idents::invalid.name;
@@ -529,8 +529,9 @@ fn contains_macro_escape(attrs: &[ast::Attribute]) -> bool {
529529

530530
// Support for item-position macro invocations, exactly the same
531531
// logic as for expression-position macro invocations.
532-
pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
533-
-> SmallVector<P<ast::Item>> {
532+
pub fn expand_item_mac(it: P<ast::Item>,
533+
imported_from: Option<ast::Ident>,
534+
fld: &mut MacroExpander) -> SmallVector<P<ast::Item>> {
534535
let (extname, path_span, tts) = match it.node {
535536
ItemMac(codemap::Spanned {
536537
node: MacInvocTT(ref pth, ref tts, _),
@@ -611,7 +612,8 @@ pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
611612
});
612613
// DON'T mark before expansion.
613614
let MacroDef { name, ext }
614-
= macro_rules::add_new_extension(fld.cx, it.span, it.ident, tts);
615+
= macro_rules::add_new_extension(fld.cx, it.span, it.ident,
616+
imported_from, tts);
615617

616618
fld.cx.syntax_env.insert(intern(name.as_slice()), ext);
617619
if attr::contains_name(it.attrs.as_slice(), "macro_export") {
@@ -1190,7 +1192,7 @@ pub fn expand_crate(parse_sess: &parse::ParseSess,
11901192
expander.cx.cfg(),
11911193
expander.cx.parse_sess())
11921194
.expect("expected a serialized item");
1193-
expand_item_mac(item, &mut expander);
1195+
expand_item_mac(item, Some(crate_name), &mut expander);
11941196
}
11951197
}
11961198

src/libsyntax/ext/tt/macro_rules.rs

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

111111
struct MacroRulesMacroExpander {
112112
name: Ident,
113+
imported_from: Option<Ident>,
113114
lhses: Vec<Rc<NamedMatch>>,
114115
rhses: Vec<Rc<NamedMatch>>,
115116
}
@@ -123,6 +124,7 @@ impl TTMacroExpander for MacroRulesMacroExpander {
123124
generic_extension(cx,
124125
sp,
125126
self.name,
127+
self.imported_from,
126128
arg,
127129
self.lhses[],
128130
self.rhses[])
@@ -133,6 +135,7 @@ impl TTMacroExpander for MacroRulesMacroExpander {
133135
fn generic_extension<'cx>(cx: &'cx ExtCtxt,
134136
sp: Span,
135137
name: Ident,
138+
imported_from: Option<Ident>,
136139
arg: &[ast::TokenTree],
137140
lhses: &[Rc<NamedMatch>],
138141
rhses: &[Rc<NamedMatch>])
@@ -156,6 +159,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
156159
};
157160
// `None` is because we're not interpolating
158161
let mut arg_rdr = new_tt_reader(&cx.parse_sess().span_diagnostic,
162+
None,
159163
None,
160164
arg.iter()
161165
.map(|x| (*x).clone())
@@ -177,6 +181,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
177181
// rhs has holes ( `$id` and `$(...)` that need filled)
178182
let trncbr = new_tt_reader(&cx.parse_sess().span_diagnostic,
179183
Some(named_matches),
184+
imported_from,
180185
rhs);
181186
let p = Parser::new(cx.parse_sess(), cx.cfg(), box trncbr);
182187
// Let the context choose how to interpret the result.
@@ -209,6 +214,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
209214
pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt,
210215
sp: Span,
211216
name: Ident,
217+
imported_from: Option<Ident>,
212218
arg: Vec<ast::TokenTree> )
213219
-> MacroDef {
214220

@@ -246,6 +252,7 @@ pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt,
246252

247253
// Parse the macro_rules! invocation (`none` is for no interpolations):
248254
let arg_reader = new_tt_reader(&cx.parse_sess().span_diagnostic,
255+
None,
249256
None,
250257
arg.clone());
251258
let argument_map = parse_or_else(cx.parse_sess(),
@@ -266,6 +273,7 @@ pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt,
266273

267274
let exp = box MacroRulesMacroExpander {
268275
name: name,
276+
imported_from: imported_from,
269277
lhses: lhses,
270278
rhses: rhses,
271279
};

src/libsyntax/ext/tt/transcribe.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use codemap::{Span, DUMMY_SP};
1515
use diagnostic::SpanHandler;
1616
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
1717
use parse::token::{Eof, DocComment, Interpolated, MatchNt, SubstNt};
18-
use parse::token::{Token, NtIdent};
18+
use parse::token::{Token, NtIdent, SpecialMacroVar};
1919
use parse::token;
2020
use parse::lexer::TokenAndSpan;
2121

@@ -39,6 +39,10 @@ pub struct TtReader<'a> {
3939
stack: Vec<TtFrame>,
4040
/* for MBE-style macro transcription */
4141
interpolations: HashMap<Ident, Rc<NamedMatch>>,
42+
imported_from: Option<Ident>,
43+
44+
// Some => return imported_from as the next token
45+
crate_name_next: Option<Span>,
4246
repeat_idx: Vec<uint>,
4347
repeat_len: Vec<uint>,
4448
/* cached: */
@@ -53,6 +57,7 @@ pub struct TtReader<'a> {
5357
/// should) be none.
5458
pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler,
5559
interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
60+
imported_from: Option<Ident>,
5661
src: Vec<ast::TokenTree> )
5762
-> TtReader<'a> {
5863
let mut r = TtReader {
@@ -71,6 +76,8 @@ pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler,
7176
None => HashMap::new(),
7277
Some(x) => x,
7378
},
79+
imported_from: imported_from,
80+
crate_name_next: None,
7481
repeat_idx: Vec::new(),
7582
repeat_len: Vec::new(),
7683
desugar_doc_comments: false,
@@ -162,6 +169,14 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
162169
sp: r.cur_span.clone(),
163170
};
164171
loop {
172+
match r.crate_name_next.take() {
173+
None => (),
174+
Some(sp) => {
175+
r.cur_span = sp;
176+
r.cur_tok = token::Ident(r.imported_from.unwrap(), token::Plain);
177+
return ret_val;
178+
},
179+
}
165180
let should_pop = match r.stack.last() {
166181
None => {
167182
assert_eq!(ret_val.tok, token::Eof);
@@ -307,6 +322,18 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
307322
sep: None
308323
});
309324
}
325+
TtToken(sp, token::SpecialVarNt(SpecialMacroVar::CrateMacroVar)) => {
326+
r.stack.last_mut().unwrap().idx += 1;
327+
328+
if r.imported_from.is_some() {
329+
r.cur_span = sp;
330+
r.cur_tok = token::ModSep;
331+
r.crate_name_next = Some(sp);
332+
return ret_val;
333+
}
334+
335+
// otherwise emit nothing and proceed to the next token
336+
}
310337
TtToken(sp, tok) => {
311338
r.cur_span = sp;
312339
r.cur_tok = tok;

src/libsyntax/parse/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>)
291291
pub fn tts_to_parser<'a>(sess: &'a ParseSess,
292292
tts: Vec<ast::TokenTree>,
293293
cfg: ast::CrateConfig) -> Parser<'a> {
294-
let trdr = lexer::new_tt_reader(&sess.span_diagnostic, None, tts);
294+
let trdr = lexer::new_tt_reader(&sess.span_diagnostic, None, None, tts);
295295
Parser::new(sess, cfg, box trdr)
296296
}
297297

src/libsyntax/parse/parser.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ use parse::classify;
7575
use parse::common::{SeqSep, seq_sep_none, seq_sep_trailing_allowed};
7676
use parse::lexer::{Reader, TokenAndSpan};
7777
use parse::obsolete::*;
78-
use parse::token::{self, MatchNt, SubstNt, InternedString};
79-
use parse::token::{keywords, special_idents};
78+
use parse::token::{self, MatchNt, SubstNt, SpecialVarNt, InternedString};
79+
use parse::token::{keywords, special_idents, SpecialMacroVar};
8080
use parse::{new_sub_parser_from_file, ParseSess};
8181
use print::pprust;
8282
use ptr::P;
@@ -2747,6 +2747,9 @@ impl<'a> Parser<'a> {
27472747
op: repeat,
27482748
num_captures: name_num
27492749
}))
2750+
} else if p.token.is_keyword_allow_following_colon(keywords::Crate) {
2751+
p.bump();
2752+
TtToken(sp, SpecialVarNt(SpecialMacroVar::CrateMacroVar))
27502753
} else {
27512754
// A nonterminal that matches or not
27522755
let namep = match p.token { token::Ident(_, p) => p, _ => token::Plain };

src/libsyntax/parse/token.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,21 @@ pub enum IdentStyle {
6161
Plain,
6262
}
6363

64+
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Show, Copy)]
65+
pub enum SpecialMacroVar {
66+
/// `$crate` will be filled in with the name of the crate a macro was
67+
/// imported from, if any.
68+
CrateMacroVar,
69+
}
70+
71+
impl SpecialMacroVar {
72+
pub fn as_str(self) -> &'static str {
73+
match self {
74+
SpecialMacroVar::CrateMacroVar => "crate",
75+
}
76+
}
77+
}
78+
6479
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Show, Copy)]
6580
pub enum Lit {
6681
Byte(ast::Name),
@@ -143,6 +158,8 @@ pub enum Token {
143158
// In right-hand-sides of MBE macros:
144159
/// A syntactic variable that will be filled in by macro expansion.
145160
SubstNt(ast::Ident, IdentStyle),
161+
/// A macro variable with special meaning.
162+
SpecialVarNt(SpecialMacroVar),
146163

147164
// Junk. These carry no data because we don't really care about the data
148165
// they *would* carry, and don't really want to allocate a new ident for
@@ -265,6 +282,13 @@ impl Token {
265282
}
266283
}
267284

285+
pub fn is_keyword_allow_following_colon(&self, kw: keywords::Keyword) -> bool {
286+
match *self {
287+
Ident(sid, _) => { kw.to_name() == sid.name }
288+
_ => { false }
289+
}
290+
}
291+
268292
/// Returns `true` if the token is either a special identifier, or a strict
269293
/// or reserved keyword.
270294
#[allow(non_upper_case_globals)]

src/libsyntax/print/pprust.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ pub fn token_to_string(tok: &Token) -> String {
272272
token::Comment => "/* */".to_string(),
273273
token::Shebang(s) => format!("/* shebang: {}*/", s.as_str()),
274274

275+
token::SpecialVarNt(var) => format!("${}", var.as_str()),
276+
275277
token::Interpolated(ref nt) => match *nt {
276278
token::NtExpr(ref e) => expr_to_string(&**e),
277279
token::NtMeta(ref e) => meta_item_to_string(&**e),
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)