Cleanup the hy.macros module

Add comments to the functions, reorder, make the file clearer
This commit is contained in:
Nicolas Dandrimont 2013-09-29 17:55:15 +02:00
parent 9ea153fd7e
commit d5bf328aa7
3 changed files with 69 additions and 25 deletions

View File

@ -36,7 +36,7 @@ from hy.models.float import HyFloat
from hy.models.list import HyList
from hy.models.dict import HyDict
from hy.macros import require, process
from hy.macros import require, macroexpand
from hy._compat import str_type
import hy.importer
@ -419,7 +419,7 @@ class HyASTCompiler(object):
def compile(self, tree):
try:
tree = process(tree, self.module_name)
tree = macroexpand(tree, self.module_name)
_type = type(tree)
ret = self.compile_atom(_type, tree)
if ret:

View File

@ -43,6 +43,17 @@ _hy_macros = defaultdict(dict)
def macro(name):
"""Decorator to define a macro called `name`.
This stores the macro `name` in the namespace for the module where it is
defined.
If the module where it is defined is in `hy.core`, then the macro is stored
in the default `None` namespace.
This function is called from the `defmacro` special form in the compiler.
"""
def _(fn):
module_name = fn.__module__
if module_name.startswith("hy.core"):
@ -52,20 +63,20 @@ def macro(name):
return _
def require(source_module_name, target_module_name):
macros = _hy_macros[source_module_name]
refs = _hy_macros[target_module_name]
def require(source_module, target_module):
"""Load the macros from `source_module` in the namespace of
`target_module`.
This function is called from the `require` special form in the compiler.
"""
macros = _hy_macros[source_module]
refs = _hy_macros[target_module]
for name, macro in macros.items():
refs[name] = macro
def _wrap_value(x):
wrapper = _wrappers.get(type(x))
if wrapper is None:
return x
else:
return wrapper(x)
# type -> wrapping function mapping for _wrap_value
_wrappers = {
int: HyInteger,
bool: lambda x: HySymbol("True") if x else HySymbol("False"),
@ -77,27 +88,60 @@ _wrappers = {
}
def process(tree, module_name):
load_macros(module_name)
old = None
while old != tree:
old = tree
tree = macroexpand(tree, module_name)
return tree
def _wrap_value(x):
"""Wrap `x` into the corresponding Hy type.
This allows a macro to return an unquoted expression transparently.
"""
wrapper = _wrappers.get(type(x))
if wrapper is None:
return x
else:
return wrapper(x)
def load_macros(module_name):
"""Load the hy builtin macros for module `module_name`.
Modules from `hy.core` can only use the macros from CORE_MACROS.
Other modules get the macros from CORE_MACROS and EXTRA_MACROS.
"""
def _import(module, module_name=module_name):
"__import__ a module, avoiding recursions"
if module != module_name:
__import__(module)
for module in CORE_MACROS:
__import__(module)
_import(module)
if module_name.startswith("hy.core"):
return
for module in EXTRA_MACROS:
__import__(module)
_import(module)
def macroexpand(tree, module_name):
"""Expand the toplevel macros for the `tree`.
Load the macros from the given `module_name`, then expand the (top-level)
macros in `tree` until it stops changing.
"""
load_macros(module_name)
old = None
while old != tree:
old = tree
tree = macroexpand_1(tree, module_name)
return tree
def macroexpand_1(tree, module_name):
"""Expand the toplevel macro from `tree` once, in the context of
`module_name`."""
if isinstance(tree, HyExpression):
if tree == []:
return tree

View File

@ -1,5 +1,5 @@
from hy.macros import macro, process
from hy.macros import macro, macroexpand
from hy.lex import tokenize
from hy.models.string import HyString
@ -16,14 +16,14 @@ def tmac(*tree):
def test_preprocessor_simple():
""" Test basic macro expansion """
obj = process(tokenize('(test "one" "two")')[0], __name__)
obj = macroexpand(tokenize('(test "one" "two")')[0], __name__)
assert obj == HyList(["one", "two"])
assert type(obj) == HyList
def test_preprocessor_expression():
""" Test that macro expansion doesn't recurse"""
obj = process(tokenize('(test (test "one" "two"))')[0], __name__)
obj = macroexpand(tokenize('(test (test "one" "two"))')[0], __name__)
assert type(obj) == HyList
assert type(obj[0]) == HyExpression
@ -34,4 +34,4 @@ def test_preprocessor_expression():
obj = HyList([HyString("one"), HyString("two")])
obj = tokenize('(shill ["one" "two"])')[0][1]
assert obj == process(obj, '')
assert obj == macroexpand(obj, '')