Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 20 additions & 16 deletions macropy/core/macros.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def macro_stub(func):

MacroData = collections.namedtuple('MacroData', ['macro', 'macro_tree',
'body_tree', 'call_args',
'kwargs', 'name'])
'call_kwargs', 'extrakws', 'name'])

MacroData.__doc__ = """
Contains a macro's detailed informations needed to expand it.
Expand Down Expand Up @@ -103,22 +103,25 @@ def get_macro_details(self, macro_tree):
"""Given an AST tree of a macro, returns detailed informations about it.

:param macro_tree: an AST tree
:returns: A tuple containing tree elements:
:returns: A tuple containing four elements:
- the name of the macro;
- the tree containing the macro itself (it is *macro_tree*
itself as of now);
- the arguments to the macro invocation.
- arguments to the macro invocation;
- named arguments to the macro invocation.

"""
if isinstance(macro_tree, ast.Call):
call_args = tuple(macro_tree.args)
call_kwargs = {x.arg: x.value for x in macro_tree.keywords}
macro_tree = macro_tree.func
else:
call_args = ()
call_kwargs = {}
if isinstance(macro_tree, ast.Name):
return macro_tree.id, macro_tree, call_args
return macro_tree.id, macro_tree, call_args, call_kwargs
else:
return None, macro_tree, call_args
return None, macro_tree, call_args, call_kwargs

@abstractmethod
def detect_macro(self, in_tree):
Expand Down Expand Up @@ -147,10 +150,10 @@ def detect_macro(self, in_tree):
if (isinstance(in_tree, ast.Subscript) and
type(in_tree.slice) is ast.Index): # noqa: E129
body_tree = in_tree.slice.value
name, macro_tree, call_args = self.get_macro_details(in_tree.value)
name, macro_tree, call_args, call_kwargs = self.get_macro_details(in_tree.value)
if name is not None and name in self.registry:
new_tree = yield MacroData(self.registry[name], macro_tree,
body_tree, call_args, {}, name)
body_tree, call_args, call_kwargs, {}, name)
assert isinstance(new_tree, ast.expr), ('Wrong type %r' %
type(new_tree))
new_tree = ast.Expr(new_tree)
Expand All @@ -171,13 +174,12 @@ def detect_macro(self, in_tree):
assert isinstance(in_tree.body, list), real_repr(in_tree.body)
new_tree = None
for wi in in_tree.items:
name, macro_tree, call_args = self.get_macro_details(
name, macro_tree, call_args, call_kwargs = self.get_macro_details(
wi.context_expr)
if name is not None and name in self.registry:
new_tree = yield MacroData(self.registry[name], macro_tree,
in_tree.body, call_args,
{'target': wi.optional_vars},
name)
in_tree.body, call_args, call_kwargs,
{'target': wi.optional_vars}, name)

if new_tree:
if isinstance(new_tree, ast.expr):
Expand Down Expand Up @@ -212,7 +214,7 @@ def detect_macro(self, in_tree):
additions = []
# process each decorator from the innermost outwards
for dec in rev_decs:
name, macro_tree, call_args = self.get_macro_details(dec)
name, macro_tree, call_args, call_kwargs = self.get_macro_details(dec)
# if the decorator is not a macro, add it to a list
# for later re-insertion, either before executing an
# outer macro or at the end of the loop if no macro is found
Expand All @@ -226,7 +228,7 @@ def detect_macro(self, in_tree):
tree.decorator_list)
seen_decs = []
tree = yield MacroData(self.registry[name], macro_tree, tree,
call_args, {}, name)
call_args, call_kwargs, {}, name)
if type(tree) is list:
additions = tree[1:]
tree = tree[0]
Expand Down Expand Up @@ -400,7 +402,7 @@ def create_single_macro_expand_generator(self, mfunc, *args, **kwargs):
def gen_macro_expand_single(tree):
return self.macro_expand_single(MacroData(
(mfunc, sys.modules[mfunc.__module__]),
tree, tree, args, kwargs, mfunc.__name__))
tree, tree, args, kwargs, {}, mfunc.__name__))
return gen_macro_expand_single

def expand_macro(self, mfunc, tree=None, *args, **kwargs):
Expand Down Expand Up @@ -497,9 +499,10 @@ def macro_expand_single(self, macro_data):
new_tree = mfunc(
tree=new_tree,
args=macro_data.call_args,
kwargs=macro_data.call_kwargs,
src=self.src,
expand_macros=self.expand_macros,
**dict(tuple(macro_data.kwargs.items()) +
**dict(tuple(macro_data.extrakws.items()) +
tuple(self.file_vars.items()))
)
# the result is a generator, treat it like a
Expand Down Expand Up @@ -527,11 +530,12 @@ def macro_expand_single(self, macro_data):
new_tree = function(
tree=new_tree,
args=macro_data.call_args,
kwargs=macro_data.call_kwargs,
src=self.src,
expand_macros=self.expand_macros,
lineno=macro_data.macro_tree.lineno,
col_offset=macro_data.macro_tree.col_offset,
**dict(tuple(macro_data.kwargs.items()) +
**dict(tuple(macro_data.extrakws.items()) +
tuple(self.file_vars.items()))
)
# yield it for one more walking
Expand Down
6 changes: 4 additions & 2 deletions macropy/core/test/macros/argument.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
from macropy.core.test.macros.argument_macros import macros, expr_macro, block_macro, decorator_macro
from macropy.core.test.macros.argument_macros import macros, expr_macro, block_macro, decorator_macro, expr_macro_with_named_args
import math

def run():
x = expr_macro(1 + math.sqrt(5))[10 + 10 + 10]

x = expr_macro_with_named_args(1 + 2 + 3, a=(1 + math.sqrt(5)))[10 + 10 + 10]

with block_macro(1 + math.sqrt(5)) as y:
x = x + 1

@decorator_macro(1 + math.sqrt(5))
def f():
pass

return x
return x
7 changes: 7 additions & 0 deletions macropy/core/test/macros/argument_macros.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@

macros = macropy.core.macros.Macros()

@macros.expr
def expr_macro_with_named_args(tree, args, kwargs, **kw):
assert "a" in kwargs, kwargs
assert macropy.core.unparse(kwargs["a"]) == "(1 + math.sqrt(5))", macropy.core.unparse(kwargs["a"])
assert list(map(macropy.core.unparse, args)) == ["((1 + 2) + 3)"], macropy.core.unparse(args)
return tree

@macros.expr
def expr_macro(tree, args, **kw):
assert list(map(macropy.core.unparse, args)) == ["(1 + math.sqrt(5))"], macropy.core.unparse(args)
Expand Down