From 1aa86ae6773388fc441064fb0b19d0b2c0f524fc Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sat, 17 May 2014 19:02:02 -0400 Subject: [PATCH 01/10] Add AST support for macro identifiers --- src/libsyntax/ast.rs | 41 +++++++++++++++++++ src/libsyntax/ext/base.rs | 4 ++ src/libsyntax/ext/expand.rs | 82 +++++++++++++++++++++++++++++++++---- src/libsyntax/fold.rs | 5 ++- src/libsyntax/visit.rs | 5 ++- 5 files changed, 126 insertions(+), 11 deletions(-) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index e7f892d77ceaa..e24d7974886c8 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -19,6 +19,8 @@ use parse::token; use std::fmt; use std::fmt::Show; +use std::cell::RefCell; +use std::local_data::Ref; use std::option::Option; use std::rc::Rc; use serialize::{Encodable, Decodable, Encoder, Decoder}; @@ -44,9 +46,48 @@ pub struct Ident { pub ctxt: SyntaxContext } +pub static MACRO_CTXT: SyntaxContext = 0xffffffffu32; + +local_data_key!(key_macro_idents: RefCell>) + +fn get_macro_idents() -> Ref>> { + match key_macro_idents.get() { + Some(x) => x, + None => { + let x = RefCell::new(Vec::new()); + key_macro_idents.replace(Some(x)); + get_macro_idents() + } + } +} + impl Ident { /// Construct an identifier with the given name and an empty context: pub fn new(name: Name) -> Ident { Ident {name: name, ctxt: EMPTY_CTXT}} + + pub fn new_macro_ident(a: Mac) -> Ident { + let r = get_macro_idents(); + let mut macro_idents = r.borrow_mut(); + macro_idents.push(a); + let idx: Name = macro_idents.len() as u32 - 1; + Ident {name: idx, ctxt: MACRO_CTXT} + } + + pub fn get_macro_ident(&self) -> Option { + match self.ctxt { + MACRO_CTXT => { + let r = get_macro_idents(); + let mut macro_idents = r.borrow_mut(); + let i = self.name as uint; + if i < macro_idents.len() { + Some(macro_idents.get(i).clone()) + } else { + None + } + }, + _ => None + } + } } impl Eq for Ident { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 06b56bbe472a2..4bbf4991a9e9d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -114,6 +114,10 @@ pub trait MacResult { fn make_items(&self) -> Option> { None } + /// Create an identifier + fn make_ident(&self) -> Option { + None + } /// Create a statement. /// diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1898e8bf000a8..86de677dde3f0 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -363,6 +363,57 @@ pub fn contains_macro_escape(attrs: &[ast::Attribute]) -> bool { attr::contains_name(attrs, "macro_escape") } +fn expand_ident(ident: Ident, fld: &mut MacroExpander) -> Ident { + match ident.get_macro_ident() { + None => ident, + Some(mac) => { + let MacInvocTT(ref pth, ref tts, _) = mac.node; + let extname = pth.segments.get(0).identifier; + let extnamestr = token::get_ident(extname); + match fld.extsbox.find(&extname.name) { + None => { + fld.cx.span_err(pth.span, format!("macro undefined: '{}'", extnamestr)); + parse::token::special_idents::invalid + } + + Some(&NormalTT(ref expandfun, exp_span)) => { + fld.cx.bt_push(ExpnInfo { + call_site: mac.span, + callee: NameAndSpan { + name: extnamestr.get().to_strbuf(), + format: MacroBang, + span: exp_span, + } + }); + let fm = fresh_mark(); + // mark before expansion: + let marked_tts = mark_tts(tts.as_slice(), fm); + + // TODO: Read expand_expr to see whether we want + // original_span(fld.cx) or mac.span + let mac_span = original_span(fld.cx); + + match expandfun.expand(fld.cx, + mac_span.call_site, + marked_tts.as_slice()).make_ident() { + Some(ident) => ident, + None => { + fld.cx.span_err(pth.span, + format!("non-ident macro in ident pos: {}", + extnamestr)); + parse::token::special_idents::invalid + } + } + } + _ => { + debug!("FIXME"); + parse::token::special_idents::invalid + } + } + } + } +} + // Support for item-position macro invocations, exactly the same // logic as for expression-position macro invocations. pub fn expand_item_mac(it: @ast::Item, fld: &mut MacroExpander) @@ -812,12 +863,17 @@ pub struct IdentRenamer<'a> { impl<'a> Folder for IdentRenamer<'a> { fn fold_ident(&mut self, id: Ident) -> Ident { - let new_ctxt = self.renames.iter().fold(id.ctxt, |ctxt, &(from, to)| { - mtwt::new_rename(from, to, ctxt) - }); - Ident { - name: id.name, - ctxt: new_ctxt, + match id.get_macro_ident() { + Some(_mac) => id, + None => { + let new_ctxt = self.renames.iter().fold(id.ctxt, |ctxt, &(from, to)| { + mtwt::new_rename(from, to, ctxt) + }); + Ident { + name: id.name, + ctxt: new_ctxt, + } + } } } } @@ -849,6 +905,10 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> { expand_expr(expr, self) } + fn fold_ident(&mut self, ident: ast::Ident) -> ast::Ident { + expand_ident(ident, self) + } + fn fold_item(&mut self, item: @ast::Item) -> SmallVector<@ast::Item> { expand_item(item, self) } @@ -903,9 +963,13 @@ struct Marker { mark: Mrk } impl Folder for Marker { fn fold_ident(&mut self, id: Ident) -> Ident { - ast::Ident { - name: id.name, - ctxt: mtwt::new_mark(self.mark, id.ctxt) + match id.get_macro_ident() { + Some(_mac) => id, + None => + ast::Ident { + name: id.name, + ctxt: mtwt::new_mark(self.mark, id.ctxt) + } } } fn fold_mac(&mut self, m: &ast::Mac) -> ast::Mac { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 10df264676e33..d9c5432e648e9 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -678,7 +678,10 @@ pub fn noop_fold_item(i: &Item, folder: &mut T) -> SmallVector<@Item> ItemImpl(_, ref maybe_trait, ty, _) => { ast_util::impl_pretty_name(maybe_trait, ty) } - _ => i.ident + _ => match i.ident.get_macro_ident() { + Some(mac) => ast::Ident::new_macro_ident(folder.fold_mac(&mac)), + None => i.ident, + } }; SmallVector::one(@Item { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index ce10d0db3ba75..0d4e3f7312e17 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -209,7 +209,10 @@ pub fn walk_trait_ref_helper>(visitor: &mut V, } pub fn walk_item>(visitor: &mut V, item: &Item, env: E) { - visitor.visit_ident(item.span, item.ident, env.clone()); + match item.ident.get_macro_ident() { + Some(mac) => visitor.visit_mac(&mac, env.clone()), + None => visitor.visit_ident(item.span, item.ident, env.clone()), + } match item.node { ItemStatic(typ, _, expr) => { visitor.visit_ty(typ, env.clone()); From 116161bbef58f499b1ebb2cc40de2271bbe70864 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sat, 17 May 2014 19:02:37 -0400 Subject: [PATCH 02/10] Add parser support for macro identifiers --- src/libsyntax/parse/parser.rs | 61 ++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 92e5f8da6aa7e..0384b69cb4a35 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -479,6 +479,35 @@ impl<'a> Parser<'a> { self.commit_stmt(s, &[edible], &[]) } + pub fn parse_ident_or_macro(&mut self) -> ast::Ident { + self.check_strict_keywords(); + self.check_reserved_keywords(); + match self.token { + token::IDENT(_, _) if self.look_ahead(1, |t| *t == token::NOT) => { + // we have a macro identifier + let pth = self.parse_path(NoTypesAllowed).path; + self.expect(&token::NOT); + + // eat a matched-delimiter token tree: + let tts = match token::close_delimiter_for(&self.token) { + Some(ket) => { + self.bump(); + self.parse_seq_to_end(&ket, + seq_sep_none(), + |p| p.parse_token_tree()) + } + None => self.fatal("expected open delimiter") + }; + let m = ast::MacInvocTT(pth, tts, EMPTY_CTXT); + let m: ast::Mac = codemap::Spanned { node: m, + span: mk_sp(self.span.lo, + self.span.hi) }; + ast::Ident::new_macro_ident(m) + } + _ => self.parse_ident() + } + } + pub fn parse_ident(&mut self) -> ast::Ident { self.check_strict_keywords(); self.check_reserved_keywords(); @@ -1125,7 +1154,7 @@ impl<'a> Parser<'a> { let style = p.parse_fn_style(); // NB: at the moment, trait methods are public by default; this // could change. - let ident = p.parse_ident(); + let ident = p.parse_ident_or_macro(); let generics = p.parse_generics(); @@ -1196,7 +1225,7 @@ impl<'a> Parser<'a> { pub fn parse_ty_field(&mut self) -> TypeField { let lo = self.span.lo; let mutbl = self.parse_mutability(); - let id = self.parse_ident(); + let id = self.parse_ident_or_macro(); self.expect(&token::COLON); let ty = self.parse_ty(false); let hi = ty.span.hi; @@ -1684,7 +1713,7 @@ impl<'a> Parser<'a> { // parse ident COLON expr pub fn parse_field(&mut self) -> Field { let lo = self.span.lo; - let i = self.parse_ident(); + let i = self.parse_ident_or_macro(); let hi = self.last_span.hi; self.expect(&token::COLON); let e = self.parse_expr(); @@ -2778,7 +2807,7 @@ impl<'a> Parser<'a> { BindByValue(MutImmutable) }; - let fieldname = self.parse_ident(); + let fieldname = self.parse_ident_or_macro(); let subpat = if self.token == token::COLON { match bind_type { @@ -3120,7 +3149,7 @@ impl<'a> Parser<'a> { if !is_plain_ident(&self.token) { self.fatal("expected ident"); } - let name = self.parse_ident(); + let name = self.parse_ident_or_macro(); self.expect(&token::COLON); let ty = self.parse_ty(false); spanned(lo, self.last_span.hi, ast::StructField_ { @@ -3175,7 +3204,7 @@ impl<'a> Parser<'a> { let id = if token::close_delimiter_for(&self.token).is_some() { token::special_idents::invalid // no special identifier } else { - self.parse_ident() + self.parse_ident_or_macro() }; // check that we're pointing at delimiters (need to check @@ -3473,7 +3502,7 @@ impl<'a> Parser<'a> { fn parse_ty_param(&mut self) -> TyParam { let sized = self.parse_sized(); let span = self.span; - let ident = self.parse_ident(); + let ident = self.parse_ident_or_macro(); let (_, opt_bounds) = self.parse_optional_ty_param_bounds(false); // For typarams we don't care about the difference b/w "" and "". let bounds = opt_bounds.unwrap_or_default(); @@ -3813,7 +3842,7 @@ impl<'a> Parser<'a> { // parse the name and optional generic types of a function header. fn parse_fn_header(&mut self) -> (Ident, ast::Generics) { - let id = self.parse_ident(); + let id = self.parse_ident_or_macro(); let generics = self.parse_generics(); (id, generics) } @@ -3851,7 +3880,7 @@ impl<'a> Parser<'a> { let visa = self.parse_visibility(); let fn_style = self.parse_fn_style(); - let ident = self.parse_ident(); + let ident = self.parse_ident_or_macro(); let generics = self.parse_generics(); let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| { p.parse_arg() @@ -3876,7 +3905,7 @@ impl<'a> Parser<'a> { // parse trait Foo { ... } fn parse_item_trait(&mut self) -> ItemInfo { - let ident = self.parse_ident(); + let ident = self.parse_ident_or_macro(); let tps = self.parse_generics(); let sized = self.parse_for_sized(); @@ -3967,7 +3996,7 @@ impl<'a> Parser<'a> { // parse struct Foo { ... } fn parse_item_struct(&mut self, is_virtual: bool) -> ItemInfo { - let class_name = self.parse_ident(); + let class_name = self.parse_ident_or_macro(); let generics = self.parse_generics(); let super_struct = if self.eat(&token::COLON) { @@ -4157,7 +4186,7 @@ impl<'a> Parser<'a> { fn parse_item_const(&mut self) -> ItemInfo { let m = if self.eat_keyword(keywords::Mut) {MutMutable} else {MutImmutable}; - let id = self.parse_ident(); + let id = self.parse_ident_or_macro(); self.expect(&token::COLON); let ty = self.parse_ty(false); self.expect(&token::EQ); @@ -4305,7 +4334,7 @@ impl<'a> Parser<'a> { self.expect_keyword(keywords::Static); let mutbl = self.eat_keyword(keywords::Mut); - let ident = self.parse_ident(); + let ident = self.parse_ident_or_macro(); self.expect(&token::COLON); let ty = self.parse_ty(false); let hi = self.span.hi; @@ -4429,7 +4458,7 @@ impl<'a> Parser<'a> { // parse type Foo = Bar; fn parse_item_type(&mut self) -> ItemInfo { - let ident = self.parse_ident(); + let ident = self.parse_ident_or_macro(); let tps = self.parse_generics(); self.expect(&token::EQ); let ty = self.parse_ty(false); @@ -4469,7 +4498,7 @@ impl<'a> Parser<'a> { let kind; let mut args = Vec::new(); let mut disr_expr = None; - ident = self.parse_ident(); + ident = self.parse_ident_or_macro(); if self.eat(&token::LBRACE) { // Parse a struct variant. all_nullary = false; @@ -4520,7 +4549,7 @@ impl<'a> Parser<'a> { // parse an "enum" declaration fn parse_item_enum(&mut self) -> ItemInfo { - let id = self.parse_ident(); + let id = self.parse_ident_or_macro(); let generics = self.parse_generics(); self.expect(&token::LBRACE); From 66e3016b620cb8145cb94c9e90122f1e853cc256 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sat, 17 May 2014 19:04:08 -0400 Subject: [PATCH 03/10] concat_idents: Support usage in identifier position --- src/libsyntax/ext/concat_idents.rs | 52 +++++++++++++++++++----------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index 0e168e7b33b70..722317486a317 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -18,6 +18,38 @@ use parse::token::{str_to_ident}; use std::strbuf::StrBuf; +pub struct ConcatIdent { + span: Span, + ident: ast::Ident, +} + +impl MacResult for ConcatIdent { + fn make_expr(&self) -> Option<@ast::Expr> { + let e = @ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprPath( + ast::Path { + span: self.span, + global: false, + segments: vec!( + ast::PathSegment { + identifier: self.ident, + lifetimes: Vec::new(), + types: OwnedSlice::empty(), + } + ) + } + ), + span: self.span, + }; + MacExpr::new(e).make_expr() + } + + fn make_ident(&self) -> Option { + Some(self.ident) + } +} + pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box { let mut res_str = StrBuf::new(); @@ -43,23 +75,5 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) } } let res = str_to_ident(res_str.into_owned()); - - let e = @ast::Expr { - id: ast::DUMMY_NODE_ID, - node: ast::ExprPath( - ast::Path { - span: sp, - global: false, - segments: vec!( - ast::PathSegment { - identifier: res, - lifetimes: Vec::new(), - types: OwnedSlice::empty(), - } - ) - } - ), - span: sp, - }; - MacExpr::new(e) + box ConcatIdent { span: sp, ident: res } as Box } From 7a40c794e6fb5518aaa69938a83a1474e2ece7da Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sat, 17 May 2014 20:58:05 -0400 Subject: [PATCH 04/10] visit: Walk over macro identifiers --- src/libsyntax/visit.rs | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 0d4e3f7312e17..4ababce97c6d2 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -158,12 +158,12 @@ pub fn walk_mod>(visitor: &mut V, module: &Mod, env: E) pub fn walk_view_item>(visitor: &mut V, vi: &ViewItem, env: E) { match vi.node { ViewItemExternCrate(name, _, _) => { - visitor.visit_ident(vi.span, name, env) + walk_ident(visitor, vi.span, name, env) } ViewItemUse(ref vp) => { match vp.node { ViewPathSimple(ident, ref path, id) => { - visitor.visit_ident(vp.span, ident, env.clone()); + walk_ident(visitor, vp.span, ident, env.clone()); visitor.visit_path(path, id, env.clone()); } ViewPathGlob(ref path, id) => { @@ -171,7 +171,7 @@ pub fn walk_view_item>(visitor: &mut V, vi: &ViewItem, e } ViewPathList(ref path, ref list, _) => { for id in list.iter() { - visitor.visit_ident(id.span, id.node.name, env.clone()) + walk_ident(visitor, id.span, id.node.name, env.clone()) } walk_path(visitor, path, env.clone()); } @@ -208,11 +208,18 @@ pub fn walk_trait_ref_helper>(visitor: &mut V, visitor.visit_path(&trait_ref.path, trait_ref.ref_id, env) } -pub fn walk_item>(visitor: &mut V, item: &Item, env: E) { - match item.ident.get_macro_ident() { +pub fn walk_ident>(visitor: &mut V, + span: Span, + ident: Ident, + env: E) { + match ident.get_macro_ident() { Some(mac) => visitor.visit_mac(&mac, env.clone()), - None => visitor.visit_ident(item.span, item.ident, env.clone()), + None => visitor.visit_ident(span, ident, env.clone()), } +} + +pub fn walk_item>(visitor: &mut V, item: &Item, env: E) { + walk_ident(visitor, item.span, item.ident, env.clone()); match item.node { ItemStatic(typ, _, expr) => { visitor.visit_ty(typ, env.clone()); @@ -296,7 +303,7 @@ pub fn walk_variant>(visitor: &mut V, variant: &Variant, generics: &Generics, env: E) { - visitor.visit_ident(variant.span, variant.node.name, env.clone()); + walk_ident(visitor, variant.span, variant.node.name, env.clone()); match variant.node.kind { TupleVariantKind(ref variant_arguments) => { @@ -400,7 +407,7 @@ fn walk_lifetime_decls>(visitor: &mut V, pub fn walk_path>(visitor: &mut V, path: &Path, env: E) { for segment in path.segments.iter() { - visitor.visit_ident(path.span, segment.identifier, env.clone()); + walk_ident(visitor, path.span, segment.identifier, env.clone()); for &typ in segment.types.iter() { visitor.visit_ty(typ, env.clone()); @@ -466,7 +473,7 @@ pub fn walk_pat>(visitor: &mut V, pattern: &Pat, env: E) pub fn walk_foreign_item>(visitor: &mut V, foreign_item: &ForeignItem, env: E) { - visitor.visit_ident(foreign_item.span, foreign_item.ident, env.clone()); + walk_ident(visitor, foreign_item.span, foreign_item.ident, env.clone()); match foreign_item.node { ForeignItemFn(function_declaration, ref generics) => { @@ -521,7 +528,7 @@ pub fn walk_fn_decl>(visitor: &mut V, pub fn walk_method_helper>(visitor: &mut V, method: &Method, env: E) { - visitor.visit_ident(method.span, method.ident, env.clone()); + walk_ident(visitor, method.span, method.ident, env.clone()); visitor.visit_fn(&FkMethod(method.ident, &method.generics, method), method.decl, method.body, @@ -556,7 +563,7 @@ pub fn walk_fn>(visitor: &mut V, pub fn walk_ty_method>(visitor: &mut V, method_type: &TypeMethod, env: E) { - visitor.visit_ident(method_type.span, method_type.ident, env.clone()); + walk_ident(visitor, method_type.span, method_type.ident, env.clone()); visitor.visit_explicit_self(&method_type.explicit_self, env.clone()); for argument_type in method_type.decl.inputs.iter() { visitor.visit_ty(argument_type.ty, env.clone()) @@ -593,7 +600,7 @@ pub fn walk_struct_field>(visitor: &mut V, env: E) { match struct_field.node.kind { NamedField(name, _) => { - visitor.visit_ident(struct_field.span, name, env.clone()) + walk_ident(visitor, struct_field.span, name, env.clone()) } _ => {} } From 26bd41b2557eb3c6d86d78fa993751f7486de98a Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sat, 17 May 2014 21:05:14 -0400 Subject: [PATCH 05/10] fold: Fold over all ident macros --- src/libsyntax/fold.rs | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index d9c5432e648e9..e3940989f735c 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -273,7 +273,7 @@ pub trait Folder { span: self.new_span(p.span), global: p.global, segments: p.segments.iter().map(|segment| ast::PathSegment { - identifier: self.fold_ident(segment.identifier), + identifier: fold_ident_or_macro(segment.identifier, self), lifetimes: segment.lifetimes.iter().map(|l| self.fold_lifetime(l)).collect(), types: segment.types.iter().map(|&typ| self.fold_ty(typ)).collect(), }).collect() @@ -408,18 +408,25 @@ pub fn fold_tts(tts: &[TokenTree], fld: &mut T) -> Vec { sep.as_ref().map(|tok|maybe_fold_ident(tok,fld)), is_optional), TTNonterminal(sp,ref ident) => - TTNonterminal(sp,fld.fold_ident(*ident)) + TTNonterminal(sp,fold_ident_or_macro(*ident, fld)) } }).collect() } +fn fold_ident_or_macro(i: Ident, folder: &mut T) -> Ident { + match i.get_macro_ident() { + Some(mac) => ast::Ident::new_macro_ident(folder.fold_mac(&mac)), + None => folder.fold_ident(i) + } +} + // apply ident folder if it's an ident, otherwise leave it alone fn maybe_fold_ident(t: &token::Token, fld: &mut T) -> token::Token { match *t { token::IDENT(id, followed_by_colons) => { - token::IDENT(fld.fold_ident(id), followed_by_colons) + token::IDENT(fold_ident_or_macro(id, fld), followed_by_colons) } - token::LIFETIME(id) => token::LIFETIME(fld.fold_ident(id)), + token::LIFETIME(id) => token::LIFETIME(fold_ident_or_macro(id, fld)), _ => (*t).clone() } } @@ -518,7 +525,7 @@ fn fold_struct_field(f: &StructField, fld: &mut T) -> StructField { fn fold_field_(field: Field, folder: &mut T) -> Field { ast::Field { - ident: respan(field.ident.span, folder.fold_ident(field.ident.node)), + ident: respan(field.ident.span, fold_ident_or_macro(field.ident.node, folder)), expr: folder.fold_expr(field.expr), span: folder.new_span(field.span), } @@ -641,7 +648,7 @@ pub fn noop_fold_type_method(m: &TypeMethod, fld: &mut T) -> TypeMeth let id = fld.new_id(m.id); // Needs to be first, for ast_map. TypeMethod { id: id, - ident: fld.fold_ident(m.ident), + ident: fold_ident_or_macro(m.ident, fld), attrs: m.attrs.iter().map(|a| fold_attribute_(*a, fld)).collect(), fn_style: m.fn_style, decl: fld.fold_fn_decl(m.decl), @@ -678,15 +685,12 @@ pub fn noop_fold_item(i: &Item, folder: &mut T) -> SmallVector<@Item> ItemImpl(_, ref maybe_trait, ty, _) => { ast_util::impl_pretty_name(maybe_trait, ty) } - _ => match i.ident.get_macro_ident() { - Some(mac) => ast::Ident::new_macro_ident(folder.fold_mac(&mac)), - None => i.ident, - } + _ => fold_ident_or_macro(i.ident, folder) }; SmallVector::one(@Item { id: id, - ident: folder.fold_ident(ident), + ident: fold_ident_or_macro(ident, folder), attrs: i.attrs.iter().map(|e| fold_attribute_(*e, folder)).collect(), node: node, vis: i.vis, @@ -698,7 +702,7 @@ pub fn noop_fold_foreign_item(ni: &ForeignItem, folder: &mut T) -> @F let id = folder.new_id(ni.id); // Needs to be first, for ast_map. @ForeignItem { id: id, - ident: folder.fold_ident(ni.ident), + ident: fold_ident_or_macro(ni.ident, folder), attrs: ni.attrs.iter().map(|x| fold_attribute_(*x, folder)).collect(), node: match ni.node { ForeignItemFn(ref fdec, ref generics) => { @@ -722,7 +726,7 @@ pub fn noop_fold_method(m: &Method, folder: &mut T) -> @Method { let id = folder.new_id(m.id); // Needs to be first, for ast_map. @Method { id: id, - ident: folder.fold_ident(m.ident), + ident: fold_ident_or_macro(m.ident, folder), attrs: m.attrs.iter().map(|a| fold_attribute_(*a, folder)).collect(), generics: fold_generics(&m.generics, folder), explicit_self: folder.fold_explicit_self(&m.explicit_self), @@ -801,7 +805,7 @@ pub fn noop_fold_expr(e: @Expr, folder: &mut T) -> @Expr { } ExprMethodCall(i, ref tps, ref args) => { ExprMethodCall( - respan(i.span, folder.fold_ident(i.node)), + respan(i.span, fold_ident_or_macro(i.node, folder)), tps.iter().map(|&x| folder.fold_ty(x)).collect(), args.iter().map(|&x| folder.fold_expr(x)).collect()) } @@ -830,11 +834,11 @@ pub fn noop_fold_expr(e: @Expr, folder: &mut T) -> @Expr { ExprForLoop(folder.fold_pat(pat), folder.fold_expr(iter), folder.fold_block(body), - maybe_ident.map(|i| folder.fold_ident(i))) + maybe_ident.map(|i| fold_ident_or_macro(i, folder))) } ExprLoop(body, opt_ident) => { ExprLoop(folder.fold_block(body), - opt_ident.map(|x| folder.fold_ident(x))) + opt_ident.map(|x| fold_ident_or_macro(x, folder))) } ExprMatch(expr, ref arms) => { ExprMatch(folder.fold_expr(expr), @@ -857,15 +861,15 @@ pub fn noop_fold_expr(e: @Expr, folder: &mut T) -> @Expr { } ExprField(el, id, ref tys) => { ExprField(folder.fold_expr(el), - folder.fold_ident(id), + fold_ident_or_macro(id, folder), tys.iter().map(|&x| folder.fold_ty(x)).collect()) } ExprIndex(el, er) => { ExprIndex(folder.fold_expr(el), folder.fold_expr(er)) } ExprPath(ref pth) => ExprPath(folder.fold_path(pth)), - ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|x| folder.fold_ident(x))), - ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|x| folder.fold_ident(x))), + ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|x| fold_ident_or_macro(x, folder))), + ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|x| fold_ident_or_macro(x, folder))), ExprRet(ref e) => { ExprRet(e.map(|x| folder.fold_expr(x))) } From ab2e539ce4e4d330160a0f4b548f8c194b8d9ae7 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 18 May 2014 09:40:49 -0400 Subject: [PATCH 06/10] One more expansion --- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/fold.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 86de677dde3f0..283cbeb39072b 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -229,7 +229,7 @@ fn expand_loop_block(loop_block: P, // and be renamed incorrectly. let mut rename_list = vec!(rename); let mut rename_fld = renames_to_fold(&mut rename_list); - let renamed_ident = rename_fld.fold_ident(label); + let renamed_ident = fold_ident_or_macro(label, &mut rename_fld); // The rename *must* be added to the enclosed syntax context for // `break` or `continue` to pick up because by definition they are diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index e3940989f735c..a8bef311e21e8 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -413,7 +413,7 @@ pub fn fold_tts(tts: &[TokenTree], fld: &mut T) -> Vec { }).collect() } -fn fold_ident_or_macro(i: Ident, folder: &mut T) -> Ident { +pub fn fold_ident_or_macro(i: Ident, folder: &mut T) -> Ident { match i.get_macro_ident() { Some(mac) => ast::Ident::new_macro_ident(folder.fold_mac(&mac)), None => folder.fold_ident(i) From 82665d29836e49a6d9106234f9809843b8478d92 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 18 May 2014 10:49:14 -0400 Subject: [PATCH 07/10] Oops, folded twice --- src/libsyntax/fold.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index a8bef311e21e8..e40c674570875 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -685,7 +685,7 @@ pub fn noop_fold_item(i: &Item, folder: &mut T) -> SmallVector<@Item> ItemImpl(_, ref maybe_trait, ty, _) => { ast_util::impl_pretty_name(maybe_trait, ty) } - _ => fold_ident_or_macro(i.ident, folder) + _ => i.ident }; SmallVector::one(@Item { From a02e157dad5687a2c3e6b9cf3fcb40a9a5d9f0c5 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 18 May 2014 11:18:52 -0400 Subject: [PATCH 08/10] Clear macro idents after expansion --- src/librustc/driver/driver.rs | 1 + src/libsyntax/ast.rs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 5f9fd7124a9e9..8aa4b5909763b 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -273,6 +273,7 @@ pub fn phase_3_run_analysis_passes(sess: Session, // Discard MTWT tables that aren't required past resolution. syntax::ext::mtwt::clear_tables(); + syntax::ast::clear_macro_idents(); let named_region_map = time(time_passes, "lifetime resolution", (), |_| middle::resolve_lifetime::krate(&sess, krate)); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index e24d7974886c8..4b47788fe2588 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -61,6 +61,10 @@ fn get_macro_idents() -> Ref>> { } } +pub fn clear_macro_idents() { + key_macro_idents.replace(None); +} + impl Ident { /// Construct an identifier with the given name and an empty context: pub fn new(name: Name) -> Ident { Ident {name: name, ctxt: EMPTY_CTXT}} From 4f1e9c11ea91d756b6ff93fed0c3ed311f7de11f Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 18 May 2014 11:19:02 -0400 Subject: [PATCH 09/10] Fix whitespace --- src/libsyntax/ext/expand.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 283cbeb39072b..84bca90d22a34 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -394,8 +394,8 @@ fn expand_ident(ident: Ident, fld: &mut MacroExpander) -> Ident { let mac_span = original_span(fld.cx); match expandfun.expand(fld.cx, - mac_span.call_site, - marked_tts.as_slice()).make_ident() { + mac_span.call_site, + marked_tts.as_slice()).make_ident() { Some(ident) => ident, None => { fld.cx.span_err(pth.span, From 2bebe8549bc999b901d87cf847288630f62ec3be Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Sun, 18 May 2014 13:28:40 -0400 Subject: [PATCH 10/10] parser: Parse macro fields --- src/libsyntax/parse/parser.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 0384b69cb4a35..6416a688c7175 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2020,6 +2020,21 @@ impl<'a> Parser<'a> { // expr.f if self.eat(&token::DOT) { match self.token { + token::LPAREN => { + let es = self.parse_unspanned_seq( + &token::LPAREN, + &token::RPAREN, + seq_sep_none(), + |p| p.parse_ident_or_macro() + ); + if es.len() == 1 { + let i = *es.get(0); + let field = self.mk_field(e, i, Vec::new()); + e = self.mk_expr(self.span.lo, self.span.hi, field) + } else { + fail!("uh oh"); + } + } token::IDENT(i, _) => { let dot = self.last_span.hi; hi = self.span.hi;