diff options
| author | Keegan McAllister <kmcallister@mozilla.com> | 2014-09-15 18:27:28 -0700 |
|---|---|---|
| committer | Keegan McAllister <kmcallister@mozilla.com> | 2015-01-05 11:38:12 -0800 |
| commit | ad7c64777380a780b42028855ad0d09932a11623 (patch) | |
| tree | e07587239681150b7c9a9d4464411d18eed31714 /src/libsyntax | |
| parent | 5e5924b79915326d81db2aebfe73d2a20b8506f1 (diff) | |
Add a special macro nonterminal $crate
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 7 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 12 | ||||
| -rw-r--r-- | src/libsyntax/ext/tt/macro_rules.rs | 8 | ||||
| -rw-r--r-- | src/libsyntax/ext/tt/transcribe.rs | 29 | ||||
| -rw-r--r-- | src/libsyntax/parse/mod.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 7 | ||||
| -rw-r--r-- | src/libsyntax/parse/token.rs | 24 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 2 |
8 files changed, 82 insertions, 9 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c9d27e304ff..55aa73b4faa 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -884,6 +884,7 @@ impl TokenTree { match *self { TtToken(_, token::DocComment(_)) => 2, TtToken(_, token::SubstNt(..)) => 2, + TtToken(_, token::SpecialVarNt(..)) => 2, TtToken(_, token::MatchNt(..)) => 3, TtDelimited(_, ref delimed) => { delimed.tts.len() + 2 @@ -925,6 +926,12 @@ impl TokenTree { TtToken(sp, token::Ident(name, name_st))]; v[index] } + (&TtToken(sp, token::SpecialVarNt(var)), _) => { + let v = [TtToken(sp, token::Dollar), + TtToken(sp, token::Ident(token::str_to_ident(var.as_str()), + token::Plain))]; + v[index] + } (&TtToken(sp, token::MatchNt(name, kind, name_st, kind_st)), _) => { let v = [TtToken(sp, token::SubstNt(name, name_st)), TtToken(sp, token::Colon), diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index a1a13f23064..325d8aa594a 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -432,7 +432,7 @@ pub fn expand_item(it: P<ast::Item>, fld: &mut MacroExpander) } let mut new_items = match it.node { - ast::ItemMac(..) => expand_item_mac(it, fld), + ast::ItemMac(..) => expand_item_mac(it, None, fld), ast::ItemMod(_) | ast::ItemForeignMod(_) => { let valid_ident = it.ident.name != parse::token::special_idents::invalid.name; @@ -529,8 +529,9 @@ fn contains_macro_escape(attrs: &[ast::Attribute]) -> bool { // Support for item-position macro invocations, exactly the same // logic as for expression-position macro invocations. -pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander) - -> SmallVector<P<ast::Item>> { +pub fn expand_item_mac(it: P<ast::Item>, + imported_from: Option<ast::Ident>, + fld: &mut MacroExpander) -> SmallVector<P<ast::Item>> { let (extname, path_span, tts) = match it.node { ItemMac(codemap::Spanned { node: MacInvocTT(ref pth, ref tts, _), @@ -611,7 +612,8 @@ pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander) }); // DON'T mark before expansion. let MacroDef { name, ext } - = macro_rules::add_new_extension(fld.cx, it.span, it.ident, tts); + = macro_rules::add_new_extension(fld.cx, it.span, it.ident, + imported_from, tts); fld.cx.syntax_env.insert(intern(name.as_slice()), ext); if attr::contains_name(it.attrs.as_slice(), "macro_export") { @@ -1190,7 +1192,7 @@ pub fn expand_crate(parse_sess: &parse::ParseSess, expander.cx.cfg(), expander.cx.parse_sess()) .expect("expected a serialized item"); - expand_item_mac(item, &mut expander); + expand_item_mac(item, Some(crate_name), &mut expander); } } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 15b75442ca2..a278604b167 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -110,6 +110,7 @@ impl<'a> MacResult for ParserAnyMacro<'a> { struct MacroRulesMacroExpander { name: Ident, + imported_from: Option<Ident>, lhses: Vec<Rc<NamedMatch>>, rhses: Vec<Rc<NamedMatch>>, } @@ -123,6 +124,7 @@ impl TTMacroExpander for MacroRulesMacroExpander { generic_extension(cx, sp, self.name, + self.imported_from, arg, self.lhses[], self.rhses[]) @@ -133,6 +135,7 @@ impl TTMacroExpander for MacroRulesMacroExpander { fn generic_extension<'cx>(cx: &'cx ExtCtxt, sp: Span, name: Ident, + imported_from: Option<Ident>, arg: &[ast::TokenTree], lhses: &[Rc<NamedMatch>], rhses: &[Rc<NamedMatch>]) @@ -157,6 +160,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, // `None` is because we're not interpolating let mut arg_rdr = new_tt_reader(&cx.parse_sess().span_diagnostic, None, + None, arg.iter() .map(|x| (*x).clone()) .collect()); @@ -177,6 +181,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, // rhs has holes ( `$id` and `$(...)` that need filled) let trncbr = new_tt_reader(&cx.parse_sess().span_diagnostic, Some(named_matches), + imported_from, rhs); let p = Parser::new(cx.parse_sess(), cx.cfg(), box trncbr); // Let the context choose how to interpret the result. @@ -209,6 +214,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt, sp: Span, name: Ident, + imported_from: Option<Ident>, arg: Vec<ast::TokenTree> ) -> MacroDef { @@ -247,6 +253,7 @@ pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt, // Parse the macro_rules! invocation (`none` is for no interpolations): let arg_reader = new_tt_reader(&cx.parse_sess().span_diagnostic, None, + None, arg.clone()); let argument_map = parse_or_else(cx.parse_sess(), cx.cfg(), @@ -266,6 +273,7 @@ pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt, let exp = box MacroRulesMacroExpander { name: name, + imported_from: imported_from, lhses: lhses, rhses: rhses, }; diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 86e81ede8b0..e4e6f5ac6b0 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -15,7 +15,7 @@ use codemap::{Span, DUMMY_SP}; use diagnostic::SpanHandler; use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; use parse::token::{Eof, DocComment, Interpolated, MatchNt, SubstNt}; -use parse::token::{Token, NtIdent}; +use parse::token::{Token, NtIdent, SpecialMacroVar}; use parse::token; use parse::lexer::TokenAndSpan; @@ -39,6 +39,10 @@ pub struct TtReader<'a> { stack: Vec<TtFrame>, /* for MBE-style macro transcription */ interpolations: HashMap<Ident, Rc<NamedMatch>>, + imported_from: Option<Ident>, + + // Some => return imported_from as the next token + crate_name_next: Option<Span>, repeat_idx: Vec<uint>, repeat_len: Vec<uint>, /* cached: */ @@ -53,6 +57,7 @@ pub struct TtReader<'a> { /// should) be none. pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler, interp: Option<HashMap<Ident, Rc<NamedMatch>>>, + imported_from: Option<Ident>, src: Vec<ast::TokenTree> ) -> TtReader<'a> { let mut r = TtReader { @@ -71,6 +76,8 @@ pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler, None => HashMap::new(), Some(x) => x, }, + imported_from: imported_from, + crate_name_next: None, repeat_idx: Vec::new(), repeat_len: Vec::new(), desugar_doc_comments: false, @@ -162,6 +169,14 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { sp: r.cur_span.clone(), }; loop { + match r.crate_name_next.take() { + None => (), + Some(sp) => { + r.cur_span = sp; + r.cur_tok = token::Ident(r.imported_from.unwrap(), token::Plain); + return ret_val; + }, + } let should_pop = match r.stack.last() { None => { assert_eq!(ret_val.tok, token::Eof); @@ -307,6 +322,18 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { sep: None }); } + TtToken(sp, token::SpecialVarNt(SpecialMacroVar::CrateMacroVar)) => { + r.stack.last_mut().unwrap().idx += 1; + + if r.imported_from.is_some() { + r.cur_span = sp; + r.cur_tok = token::ModSep; + r.crate_name_next = Some(sp); + return ret_val; + } + + // otherwise emit nothing and proceed to the next token + } TtToken(sp, tok) => { r.cur_span = sp; r.cur_tok = tok; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 8598571e5c3..3e4f2c8d4e2 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -291,7 +291,7 @@ pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>) pub fn tts_to_parser<'a>(sess: &'a ParseSess, tts: Vec<ast::TokenTree>, cfg: ast::CrateConfig) -> Parser<'a> { - let trdr = lexer::new_tt_reader(&sess.span_diagnostic, None, tts); + let trdr = lexer::new_tt_reader(&sess.span_diagnostic, None, None, tts); Parser::new(sess, cfg, box trdr) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index cc67079e538..f513692c31d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -75,8 +75,8 @@ use parse::classify; use parse::common::{SeqSep, seq_sep_none, seq_sep_trailing_allowed}; use parse::lexer::{Reader, TokenAndSpan}; use parse::obsolete::*; -use parse::token::{self, MatchNt, SubstNt, InternedString}; -use parse::token::{keywords, special_idents}; +use parse::token::{self, MatchNt, SubstNt, SpecialVarNt, InternedString}; +use parse::token::{keywords, special_idents, SpecialMacroVar}; use parse::{new_sub_parser_from_file, ParseSess}; use print::pprust; use ptr::P; @@ -2747,6 +2747,9 @@ impl<'a> Parser<'a> { op: repeat, num_captures: name_num })) + } else if p.token.is_keyword_allow_following_colon(keywords::Crate) { + p.bump(); + TtToken(sp, SpecialVarNt(SpecialMacroVar::CrateMacroVar)) } else { // A nonterminal that matches or not let namep = match p.token { token::Ident(_, p) => p, _ => token::Plain }; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index b7e89b32b70..a653190cffd 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -62,6 +62,21 @@ pub enum IdentStyle { } #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Show, Copy)] +pub enum SpecialMacroVar { + /// `$crate` will be filled in with the name of the crate a macro was + /// imported from, if any. + CrateMacroVar, +} + +impl SpecialMacroVar { + pub fn as_str(self) -> &'static str { + match self { + SpecialMacroVar::CrateMacroVar => "crate", + } + } +} + +#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Show, Copy)] pub enum Lit { Byte(ast::Name), Char(ast::Name), @@ -143,6 +158,8 @@ pub enum Token { // In right-hand-sides of MBE macros: /// A syntactic variable that will be filled in by macro expansion. SubstNt(ast::Ident, IdentStyle), + /// A macro variable with special meaning. + SpecialVarNt(SpecialMacroVar), // Junk. These carry no data because we don't really care about the data // they *would* carry, and don't really want to allocate a new ident for @@ -265,6 +282,13 @@ impl Token { } } + pub fn is_keyword_allow_following_colon(&self, kw: keywords::Keyword) -> bool { + match *self { + Ident(sid, _) => { kw.to_name() == sid.name } + _ => { false } + } + } + /// Returns `true` if the token is either a special identifier, or a strict /// or reserved keyword. #[allow(non_upper_case_globals)] diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 61b7aa408a8..27db49b65ce 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -272,6 +272,8 @@ pub fn token_to_string(tok: &Token) -> String { token::Comment => "/* */".to_string(), token::Shebang(s) => format!("/* shebang: {}*/", s.as_str()), + token::SpecialVarNt(var) => format!("${}", var.as_str()), + token::Interpolated(ref nt) => match *nt { token::NtExpr(ref e) => expr_to_string(&**e), token::NtMeta(ref e) => meta_item_to_string(&**e), |
