]> git.lizzy.rs Git - rust.git/commitdiff
introducing let-syntax
authorJohn Clements <clements@racket-lang.org>
Mon, 7 Jul 2014 16:54:08 +0000 (09:54 -0700)
committerJohn Clements <clements@racket-lang.org>
Tue, 8 Jul 2014 23:26:43 +0000 (16:26 -0700)
The let-syntax expander is different in that it doesn't apply
a mark to its token trees before expansion. This is used
for macro_rules, and it's because macro_rules is essentially
MTWT's let-syntax. You don't want to mark before expand sees
let-syntax, because there's no "after" syntax to mark again.

In some sense, the cleaner approach might be to introduce a new
AST node that macro_rules expands into; this would make it clearer
that the expansion of a macro is distinct from the addition of a
new macro binding.

This should work for now, though...

src/librustc/plugin/registry.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/expand.rs

index 587bedd502e15015d7920fc7110126c152f02512..2581ba51c2e107b1830a6a5fda3b82b971eda11c 100644 (file)
@@ -13,7 +13,7 @@
 use lint::LintPassObject;
 
 use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
-use syntax::ext::base::{IdentTT, ItemDecorator, ItemModifier, BasicMacroExpander};
+use syntax::ext::base::{IdentTT, LetSyntaxTT, ItemDecorator, ItemModifier, BasicMacroExpander};
 use syntax::ext::base::{MacroExpanderFn};
 use syntax::codemap::Span;
 use syntax::parse::token;
@@ -57,6 +57,8 @@ pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxEx
             IdentTT(ext, _) => IdentTT(ext, Some(self.krate_span)),
             ItemDecorator(ext) => ItemDecorator(ext),
             ItemModifier(ext) => ItemModifier(ext),
+            // there's probably a nicer way to signal this:
+            LetSyntaxTT(_, _) => fail!("can't register a new LetSyntax!"),
         }));
     }
 
index a540b23551b534437a80684cc0d1df3e6762a758..a2a442f8b6aa756fa8ba51abd4d365808a6c41f3 100644 (file)
@@ -264,8 +264,15 @@ pub enum SyntaxExtension {
     /// A function-like syntax extension that has an extra ident before
     /// the block.
     ///
-    /// `macro_rules!` is an `IdentTT`.
     IdentTT(Box<IdentMacroExpander + 'static>, Option<Span>),
+
+    /// An ident macro that has two properties:
+    /// - it adds a macro definition to the environment, and
+    /// - the definition it adds doesn't introduce any new
+    ///   identifiers.
+    ///
+    /// `macro_rules!` is a LetSyntaxTT
+    LetSyntaxTT(Box<IdentMacroExpander + 'static>, Option<Span>),
 }
 
 pub type NamedSyntaxExtension = (Name, SyntaxExtension);
@@ -300,7 +307,7 @@ fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension {
 
     let mut syntax_expanders = SyntaxEnv::new();
     syntax_expanders.insert(intern("macro_rules"),
-                            IdentTT(box BasicIdentMacroExpander {
+                            LetSyntaxTT(box BasicIdentMacroExpander {
                                 expander: ext::tt::macro_rules::add_new_extension,
                                 span: None,
                             },
index 69e629bb3c625142675e9f7a776449ff196738d9..709db52262d4bc344206765d11002d2a2a8d8279 100644 (file)
@@ -484,6 +484,24 @@ fn expand_item_mac(it: Gc<ast::Item>, fld: &mut MacroExpander)
             let marked_tts = mark_tts(tts.as_slice(), fm);
             expander.expand(fld.cx, it.span, it.ident, marked_tts)
         }
+        Some(&LetSyntaxTT(ref expander, span)) => {
+            if it.ident.name == parse::token::special_idents::invalid.name {
+                fld.cx.span_err(pth.span,
+                                format!("macro {}! expects an ident argument",
+                                        extnamestr.get()).as_slice());
+                return SmallVector::zero();
+            }
+            fld.cx.bt_push(ExpnInfo {
+                call_site: it.span,
+                callee: NameAndSpan {
+                    name: extnamestr.get().to_string(),
+                    format: MacroBang,
+                    span: span
+                }
+            });
+            // DON'T mark before expansion:
+            expander.expand(fld.cx, it.span, it.ident, tts)
+        }
         _ => {
             fld.cx.span_err(it.span,
                             format!("{}! is not legal in item position",