about summary refs log tree commit diff
path: root/src/libsyntax/ext
diff options
context:
space:
mode:
authorJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-10-11 03:41:48 +0000
committerJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-10-11 03:41:48 +0000
commit31e0e12e6986ca369e9e27fa713c40b174c4d573 (patch)
tree058816a4575cbfffab8d139e77aab7504fff9c0c /src/libsyntax/ext
parentd5281ef681195828173d4fe516b653ba0f9e9fbc (diff)
downloadrust-31e0e12e6986ca369e9e27fa713c40b174c4d573.tar.gz
rust-31e0e12e6986ca369e9e27fa713c40b174c4d573.zip
Add support for undetermined macro invocations.
Diffstat (limited to 'src/libsyntax/ext')
-rw-r--r--src/libsyntax/ext/base.rs14
-rw-r--r--src/libsyntax/ext/expand.rs29
2 files changed, 37 insertions, 6 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 923d5d05439..f7c88073c9d 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -522,10 +522,17 @@ pub trait Resolver {
     fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
 
     fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
-    fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option<Rc<SyntaxExtension>>;
+    fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool)
+                     -> Result<Rc<SyntaxExtension>, Determinacy>;
     fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModifier>>;
 }
 
+#[derive(Copy, Clone, Debug)]
+pub enum Determinacy {
+    Determined,
+    Undetermined,
+}
+
 pub struct DummyResolver;
 
 impl Resolver for DummyResolver {
@@ -539,8 +546,9 @@ impl Resolver for DummyResolver {
 
     fn find_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
     fn resolve_derive_mode(&mut self, _ident: ast::Ident) -> Option<Rc<MultiItemModifier>> { None }
-    fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation) -> Option<Rc<SyntaxExtension>> {
-        None
+    fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation, _force: bool)
+                     -> Result<Rc<SyntaxExtension>, Determinacy> {
+        Err(Determinacy::Determined)
     }
 }
 
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index ab7ffe36673..363ceebf0f4 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -225,13 +225,36 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         invocations.reverse();
 
         let mut expansions = Vec::new();
-        while let Some(invoc) = invocations.pop() {
+        let mut undetermined_invocations = Vec::new();
+        let (mut progress, mut force) = (false, !self.monotonic);
+        loop {
+            let invoc = if let Some(invoc) = invocations.pop() {
+                invoc
+            } else if undetermined_invocations.is_empty() {
+                break
+            } else {
+                invocations = mem::replace(&mut undetermined_invocations, Vec::new());
+                force = !mem::replace(&mut progress, false);
+                continue
+            };
+
+            let scope =
+                if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark };
+            let ext = match self.cx.resolver.resolve_invoc(scope, &invoc, force) {
+                Ok(ext) => Some(ext),
+                Err(Determinacy::Determined) => None,
+                Err(Determinacy::Undetermined) => {
+                    undetermined_invocations.push(invoc);
+                    continue
+                }
+            };
+
+            progress = true;
             let ExpansionData { depth, mark, .. } = invoc.expansion_data;
             self.cx.current_expansion = invoc.expansion_data.clone();
 
-            let scope = if self.monotonic { mark } else { orig_expansion_data.mark };
             self.cx.current_expansion.mark = scope;
-            let expansion = match self.cx.resolver.resolve_invoc(scope, &invoc) {
+            let expansion = match ext {
                 Some(ext) => self.expand_invoc(invoc, ext),
                 None => invoc.expansion_kind.dummy(invoc.span()),
             };