%PDF- %PDF-
| Direktori : /lib/python3/dist-packages/pythran/transformations/ |
| Current File : //lib/python3/dist-packages/pythran/transformations/remove_comprehension.py |
""" RemoveComprehension turns list comprehension into function calls. """
from pythran.analyses import ImportedIds
from pythran.passmanager import Transformation
import pythran.metadata as metadata
import gast as ast
from functools import reduce
class RemoveComprehension(Transformation):
"""
Turns all list comprehension from a node into new function calls.
>>> import gast as ast
>>> from pythran import passmanager, backend
>>> node = ast.parse("[x*x for x in (1,2,3)]")
>>> pm = passmanager.PassManager("test")
>>> _, node = pm.apply(RemoveComprehension, node)
>>> print(pm.dump(backend.Python, node))
list_comprehension0()
def list_comprehension0():
__target = builtins.list()
for x in (1, 2, 3):
builtins.list.append(__target, (x * x))
return __target
"""
def __init__(self):
self.count = 0
Transformation.__init__(self)
@staticmethod
def nest_reducer(x, g):
"""
Create a ast.For node from a comprehension and another node.
g is an ast.comprehension.
x is the code that have to be executed.
Examples
--------
>> [i for i in range(2)]
Becomes
>> for i in range(2):
>> ... x code with if clauses ...
It is a reducer as it can be call recursively for mutli generator.
Ex : >> [i, j for i in range(2) for j in range(4)]
"""
def wrap_in_ifs(node, ifs):
"""
Wrap comprehension content in all possibles if clauses.
Examples
--------
>> [i for i in range(2) if i < 3 if 0 < i]
Becomes
>> for i in range(2):
>> if i < 3:
>> if 0 < i:
>> ... the code from `node` ...
Note the nested ifs clauses.
"""
return reduce(lambda n, if_: ast.If(if_, [n], []), ifs, node)
return ast.For(g.target, g.iter, [wrap_in_ifs(x, g.ifs)], [], None)
def visit_AnyComp(self, node, comp_type, *path):
self.update = True
node.elt = self.visit(node.elt)
name = "{0}_comprehension{1}".format(comp_type, self.count)
self.count += 1
args = self.gather(ImportedIds, node)
self.count_iter = 0
starget = "__target"
body = reduce(self.nest_reducer,
reversed(node.generators),
ast.Expr(
ast.Call(
reduce(lambda x, y: ast.Attribute(x, y,
ast.Load()),
path[1:],
ast.Name(path[0], ast.Load(),
None, None)),
[ast.Name(starget, ast.Load(), None, None),
node.elt],
[],
)
)
)
# add extra metadata to this node
metadata.add(body, metadata.Comprehension(starget))
init = ast.Assign(
[ast.Name(starget, ast.Store(), None, None)],
ast.Call(
ast.Attribute(
ast.Name('builtins', ast.Load(), None, None),
comp_type,
ast.Load()
),
[], [],),
None)
result = ast.Return(ast.Name(starget, ast.Load(), None, None))
sargs = [ast.Name(arg, ast.Param(), None, None) for arg in args]
fd = ast.FunctionDef(name,
ast.arguments(sargs, [], None, [], [], None, []),
[init, body, result],
[], None, None)
metadata.add(fd, metadata.Local())
self.ctx.module.body.append(fd)
return ast.Call(
ast.Name(name, ast.Load(), None, None),
[ast.Name(arg.id, ast.Load(), None, None) for arg in sargs],
[],
) # no sharing !
def visit_ListComp(self, node):
return self.visit_AnyComp(node, "list",
"builtins", "list", "append")
def visit_SetComp(self, node):
return self.visit_AnyComp(node, "set", "builtins", "set", "add")
def visit_DictComp(self, node):
# this is a quickfix to match visit_AnyComp signature
# potential source of improvement there!
node.elt = ast.List(
[ast.Tuple([node.key, node.value], ast.Load())],
ast.Load()
)
return self.visit_AnyComp(node, "dict", "__dispatch__", "update")
def visit_GeneratorExp(self, node):
self.update = True
node.elt = self.visit(node.elt)
name = "generator_expression{0}".format(self.count)
self.count += 1
args = self.gather(ImportedIds, node)
self.count_iter = 0
body = reduce(self.nest_reducer,
reversed(node.generators),
ast.Expr(ast.Yield(node.elt))
)
sargs = [ast.Name(arg, ast.Param(), None, None) for arg in args]
fd = ast.FunctionDef(name,
ast.arguments(sargs, [], None, [], [], None, []),
[body], [], None, None)
metadata.add(fd, metadata.Local())
self.ctx.module.body.append(fd)
return ast.Call(
ast.Name(name, ast.Load(), None, None),
[ast.Name(arg.id, ast.Load(), None, None) for arg in sargs],
[],
) # no sharing !