Cleanup the hy.macros module
Add comments to the functions, reorder, make the file clearer
This commit is contained in:
parent
9ea153fd7e
commit
d5bf328aa7
@ -36,7 +36,7 @@ from hy.models.float import HyFloat
|
|||||||
from hy.models.list import HyList
|
from hy.models.list import HyList
|
||||||
from hy.models.dict import HyDict
|
from hy.models.dict import HyDict
|
||||||
|
|
||||||
from hy.macros import require, process
|
from hy.macros import require, macroexpand
|
||||||
from hy._compat import str_type
|
from hy._compat import str_type
|
||||||
import hy.importer
|
import hy.importer
|
||||||
|
|
||||||
@ -419,7 +419,7 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
def compile(self, tree):
|
def compile(self, tree):
|
||||||
try:
|
try:
|
||||||
tree = process(tree, self.module_name)
|
tree = macroexpand(tree, self.module_name)
|
||||||
_type = type(tree)
|
_type = type(tree)
|
||||||
ret = self.compile_atom(_type, tree)
|
ret = self.compile_atom(_type, tree)
|
||||||
if ret:
|
if ret:
|
||||||
|
82
hy/macros.py
82
hy/macros.py
@ -43,6 +43,17 @@ _hy_macros = defaultdict(dict)
|
|||||||
|
|
||||||
|
|
||||||
def macro(name):
|
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):
|
def _(fn):
|
||||||
module_name = fn.__module__
|
module_name = fn.__module__
|
||||||
if module_name.startswith("hy.core"):
|
if module_name.startswith("hy.core"):
|
||||||
@ -52,20 +63,20 @@ def macro(name):
|
|||||||
return _
|
return _
|
||||||
|
|
||||||
|
|
||||||
def require(source_module_name, target_module_name):
|
def require(source_module, target_module):
|
||||||
macros = _hy_macros[source_module_name]
|
"""Load the macros from `source_module` in the namespace of
|
||||||
refs = _hy_macros[target_module_name]
|
`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():
|
for name, macro in macros.items():
|
||||||
refs[name] = macro
|
refs[name] = macro
|
||||||
|
|
||||||
|
|
||||||
def _wrap_value(x):
|
# type -> wrapping function mapping for _wrap_value
|
||||||
wrapper = _wrappers.get(type(x))
|
|
||||||
if wrapper is None:
|
|
||||||
return x
|
|
||||||
else:
|
|
||||||
return wrapper(x)
|
|
||||||
|
|
||||||
_wrappers = {
|
_wrappers = {
|
||||||
int: HyInteger,
|
int: HyInteger,
|
||||||
bool: lambda x: HySymbol("True") if x else HySymbol("False"),
|
bool: lambda x: HySymbol("True") if x else HySymbol("False"),
|
||||||
@ -77,27 +88,60 @@ _wrappers = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def process(tree, module_name):
|
def _wrap_value(x):
|
||||||
load_macros(module_name)
|
"""Wrap `x` into the corresponding Hy type.
|
||||||
old = None
|
|
||||||
while old != tree:
|
This allows a macro to return an unquoted expression transparently.
|
||||||
old = tree
|
|
||||||
tree = macroexpand(tree, module_name)
|
"""
|
||||||
return tree
|
wrapper = _wrappers.get(type(x))
|
||||||
|
if wrapper is None:
|
||||||
|
return x
|
||||||
|
else:
|
||||||
|
return wrapper(x)
|
||||||
|
|
||||||
|
|
||||||
def load_macros(module_name):
|
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:
|
for module in CORE_MACROS:
|
||||||
__import__(module)
|
_import(module)
|
||||||
|
|
||||||
if module_name.startswith("hy.core"):
|
if module_name.startswith("hy.core"):
|
||||||
return
|
return
|
||||||
|
|
||||||
for module in EXTRA_MACROS:
|
for module in EXTRA_MACROS:
|
||||||
__import__(module)
|
_import(module)
|
||||||
|
|
||||||
|
|
||||||
def macroexpand(tree, module_name):
|
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 isinstance(tree, HyExpression):
|
||||||
if tree == []:
|
if tree == []:
|
||||||
return tree
|
return tree
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
from hy.macros import macro, process
|
from hy.macros import macro, macroexpand
|
||||||
from hy.lex import tokenize
|
from hy.lex import tokenize
|
||||||
|
|
||||||
from hy.models.string import HyString
|
from hy.models.string import HyString
|
||||||
@ -16,14 +16,14 @@ def tmac(*tree):
|
|||||||
|
|
||||||
def test_preprocessor_simple():
|
def test_preprocessor_simple():
|
||||||
""" Test basic macro expansion """
|
""" 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 obj == HyList(["one", "two"])
|
||||||
assert type(obj) == HyList
|
assert type(obj) == HyList
|
||||||
|
|
||||||
|
|
||||||
def test_preprocessor_expression():
|
def test_preprocessor_expression():
|
||||||
""" Test that macro expansion doesn't recurse"""
|
""" 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) == HyList
|
||||||
assert type(obj[0]) == HyExpression
|
assert type(obj[0]) == HyExpression
|
||||||
@ -34,4 +34,4 @@ def test_preprocessor_expression():
|
|||||||
|
|
||||||
obj = HyList([HyString("one"), HyString("two")])
|
obj = HyList([HyString("one"), HyString("two")])
|
||||||
obj = tokenize('(shill ["one" "two"])')[0][1]
|
obj = tokenize('(shill ["one" "two"])')[0][1]
|
||||||
assert obj == process(obj, '')
|
assert obj == macroexpand(obj, '')
|
||||||
|
Loading…
Reference in New Issue
Block a user