Repository: hylang/hy

Issue:
Macros
Make them native, homie.

Blocked by #50 #51 #52 and likely (practically) #33 



Discussion:

Resolving patch:
diff --git a/hy/compiler.py b/hy/compiler.py
--- a/hy/compiler.py
+++ b/hy/compiler.py
@@ -343,15 +343,24 @@ def imports_as_stmts(self, expr):
         """Convert the Result's imports to statements"""
         ret = Result()
         for module, names in self.imports.items():
-            ret += self.compile([
-                HyExpression([
-                    HySymbol("import"),
-                    HyList([
+            if None in names:
+                ret += self.compile([
+                    HyExpression([
+                        HySymbol("import"),
                         HySymbol(module),
-                        HyList([HySymbol(name) for name in sorted(names)])
-                    ])
-                ]).replace(expr)
-            ])
+                    ]).replace(expr)
+                ])
+            names = sorted(name for name in names if name)
+            if names:
+                ret += self.compile([
+                    HyExpression([
+                        HySymbol("import"),
+                        HyList([
+                            HySymbol(module),
+                            HyList([HySymbol(name) for name in names])
+                        ])
+                    ]).replace(expr)
+                ])
         self.imports = defaultdict(set)
         return ret.stmts
 
@@ -1608,19 +1617,19 @@ def compile_macro(self, expression):
                                      "for macro name" % type(name).__name__))
         name = HyString(name).replace(name)
         new_expression = HyExpression([
-            HySymbol("do"),
-            HyExpression([
-                HySymbol("import"),
-                HySymbol("hy.macros"),
-            ]),
-            HyExpression([
-                HySymbol("with_decorator"),
-                HyExpression([HySymbol("hy.macros.macro"), name]),
-                HyExpression([HySymbol("fn")] + expression),
-            ]),
+            HySymbol("with_decorator"),
+            HyExpression([HySymbol("hy.macros.macro"), name]),
+            HyExpression([HySymbol("fn")] + expression),
         ]).replace(expression)
-        hy.importer.hy_eval(new_expression, {})
-        return self.compile(new_expression)
+
+        # Compile-time hack: we want to get our new macro now
+        hy.importer.hy_eval(new_expression, {'hy': hy})
+
+        # We really want to have a `hy` import to get hy.macro in
+        ret = self.compile(new_expression)
+        ret.add_imports('hy', [None])
+
+        return ret
 
     @builds(HyInteger)
     def compile_integer(self, number):


Test patch:
diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy
--- a/tests/native_tests/language.hy
+++ b/tests/native_tests/language.hy
@@ -689,8 +689,17 @@
 
 
 (defn test-require []
+  "NATIVE: test requiring macros from python code"
   (try
     (assert (= "this won't happen" (qplah 1 2 3 4)))
   (catch [NameError]))
   (require tests.resources.tlib)
   (assert (= [1 2 3] (qplah 1 2 3))))
+
+
+(defn test-require-native []
+  "NATIVE: test requiring macros from native code"
+  (require tests.native_tests.native_macros)
+  (setv x [])
+  (rev (.append x 1) (.append x 2) (.append x 3))
+  (assert (= x [3 2 1])))
diff --git a/tests/native_tests/native_macros.hy b/tests/native_tests/native_macros.hy
new file mode 100644
--- /dev/null
+++ b/tests/native_tests/native_macros.hy
@@ -0,0 +1,10 @@
+(defmacro rev [&rest body]
+  "Execute the `body` statements in reverse"
+  (quasiquote (do (unquote-splice (list (reversed body))))))
+
+
+(defn test-rev-macro []
+  "NATIVE: test stararged native macros"
+  (setv x [])
+  (rev (.append x 1) (.append x 2) (.append x 3))
+  (assert (= x [3 2 1])))