diff --git a/hy/core/language.hy b/hy/core/language.hy index bf4fa54..8fcb615 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -45,6 +45,19 @@ (_numeric-check n) (- n 1)) +(defn disassemble [tree &optional [codegen false]] + "Dump the python AST for a given Hy tree to standard output + If the second argument is true, generate python code instead." + (import astor) + (import hy.compiler) + + (fake-source-positions tree) + (setv compiled (hy.compiler.hy_compile tree (calling-module-name))) + (print ((if codegen + astor.codegen.to_source + astor.dump) + compiled))) + (defn distinct [coll] "Return a generator from the original collection with duplicates removed" @@ -81,6 +94,15 @@ (_numeric-check n) (= (% n 2) 0)) +(defn fake-source-positions [tree] + "Fake the source positions for a given tree" + (if (and (iterable? tree) (not (string? tree))) + (for* [subtree tree] + (fake-source-positions subtree))) + (for* [attr '[start-line end-line start-column end-column]] + (if (not (hasattr tree attr)) + (setattr tree attr 1)))) + (defn filter [pred coll] "Return all elements from `coll` that pass `pred`" (let [[citer (iter coll)]] @@ -276,7 +298,7 @@ (_numeric_check n) (= n 0)) -(def *exports* '[calling-module-name cycle dec distinct drop +(def *exports* '[calling-module-name cycle dec distinct disassemble drop drop-while empty? even? filter flatten float? gensym inc instance? integer integer? iterable? iterate iterator? macroexpand macroexpand-1 neg? nil? none? diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 7153337..b188811 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -868,3 +868,23 @@ "NATIVE: Test the calling-module-name function" (assert (= (calling-module-name -1) "hy.core.language")) (assert (= (calling-module-name 0) "tests.native_tests.language"))) + + +(defn test-disassemble [] + "NATIVE: Test the disassemble function" + (import sys) + (if-python2 + (import [io [BytesIO :as StringIO]]) + (import [io [StringIO]])) + (setv prev-stdout sys.stdout) + (setv sys.stdout (StringIO)) + (disassemble '(do (leaky) (leaky) (macros))) + (setv stdout (.getvalue sys.stdout)) + (setv sys.stdout prev-stdout) + (assert (in "leaky" stdout)) + (assert (in "macros" stdout)) + (setv sys.stdout (StringIO)) + (disassemble '(do (leaky) (leaky) (macros)) true) + (setv stdout (.getvalue sys.stdout)) + (setv sys.stdout prev-stdout) + (assert (= stdout "leaky()\nleaky()\nmacros()\n")))