diff options
| author | Edward Wang <edward.yu.wang@gmail.com> | 2014-02-15 16:54:32 +0800 |
|---|---|---|
| committer | Edward Wang <edward.yu.wang@gmail.com> | 2014-02-23 21:20:37 +0800 |
| commit | 386db05df8aa8349857ad6f5486db0bdcc79f3cd (patch) | |
| tree | b85d659e88e28126c3874a194126079c280b7739 /src/libsyntax/fold.rs | |
| parent | 551da0615764853153db944063ae2e271414a71b (diff) | |
| download | rust-386db05df8aa8349857ad6f5486db0bdcc79f3cd.tar.gz rust-386db05df8aa8349857ad6f5486db0bdcc79f3cd.zip | |
Make break and continue hygienic
Makes labelled loops hygiene by performing renaming of the labels
defined in e.g. `'x: loop { ... }` and then used in break and continue
statements within loop body so that they act hygienically when used with
macros.
Closes #12262.
Diffstat (limited to 'src/libsyntax/fold.rs')
| -rw-r--r-- | src/libsyntax/fold.rs | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index e150d1685de..5f6eb86c3c8 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -353,6 +353,23 @@ fn fold_arg_<T: Folder>(a: &Arg, fld: &mut T) -> Arg { // build a new vector of tts by appling the Folder's fold_ident to // all of the identifiers in the token trees. +// +// This is part of hygiene magic. As far as hygiene is concerned, there +// are three types of let pattern bindings or loop labels: +// - those defined and used in non-macro part of the program +// - those used as part of macro invocation arguments +// - those defined and used inside macro definitions +// Lexically, type 1 and 2 are in one group and type 3 the other. If they +// clash, in order for let and loop label to work hygienically, one group +// or the other needs to be renamed. The problem is that type 2 and 3 are +// parsed together (inside the macro expand function). After being parsed and +// AST being constructed, they can no longer be distinguished from each other. +// +// For that reason, type 2 let bindings and loop labels are actually renamed +// in the form of tokens instead of AST nodes, here. There are wasted effort +// since many token::IDENT are not necessary part of let bindings and most +// token::LIFETIME are certainly not loop labels. But we can't tell in their +// token form. So this is less ideal and hacky but it works. pub fn fold_tts<T: Folder>(tts: &[TokenTree], fld: &mut T) -> ~[TokenTree] { tts.map(|tt| { match *tt { @@ -376,6 +393,7 @@ fn maybe_fold_ident<T: Folder>(t: &token::Token, fld: &mut T) -> token::Token { token::IDENT(id, followed_by_colons) => { token::IDENT(fld.fold_ident(id), followed_by_colons) } + token::LIFETIME(id) => token::LIFETIME(fld.fold_ident(id)), _ => (*t).clone() } } @@ -802,8 +820,8 @@ pub fn noop_fold_expr<T: Folder>(e: @Expr, folder: &mut T) -> @Expr { } ExprPath(ref pth) => ExprPath(folder.fold_path(pth)), ExprLogLevel => ExprLogLevel, - ExprBreak(opt_ident) => ExprBreak(opt_ident), - ExprAgain(opt_ident) => ExprAgain(opt_ident), + ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|x| folder.fold_ident(x))), + ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|x| folder.fold_ident(x))), ExprRet(ref e) => { ExprRet(e.map(|x| folder.fold_expr(x))) } |
