%PDF- %PDF-
Direktori : /lib/python3/dist-packages/pythran/transformations/ |
Current File : //lib/python3/dist-packages/pythran/transformations/normalize_tuples.py |
""" NormalizeTuples removes implicit variable -> tuple conversion. """ from pythran.analyses import Identifiers from pythran.passmanager import Transformation import gast as ast from functools import reduce from collections import OrderedDict from copy import deepcopy class ConvertToTuple(ast.NodeTransformer): def __init__(self, tuple_id, renamings): self.tuple_id = tuple_id self.renamings = renamings def visit_Name(self, node): if node.id in self.renamings: nnode = reduce( lambda x, y: ast.Subscript( x, ast.Constant(y, None), ast.Load()), self.renamings[node.id], ast.Name(self.tuple_id, ast.Load(), None, None) ) nnode.ctx = node.ctx return nnode return node class NormalizeTuples(Transformation): """ Remove implicit tuple -> variable conversion. >>> import gast as ast >>> from pythran import passmanager, backend >>> node = ast.parse("def foo(): a=(1,2.) ; i,j = a") >>> pm = passmanager.PassManager("test") >>> _, node = pm.apply(NormalizeTuples, node) >>> print(pm.dump(backend.Python, node)) def foo(): a = (1, 2.0) i = a[0] j = a[1] """ tuple_name = "__tuple" def __init__(self): Transformation.__init__(self) def get_new_id(self): i = 0 while 1: new_id = "{}{}".format(NormalizeTuples.tuple_name, i) if new_id not in self.ids: self.ids.add(new_id) return new_id else: i += 1 def traverse_tuples(self, node, state, renamings): if isinstance(node, ast.Name): if state: renamings[node.id] = state self.update = True elif isinstance(node, ast.Tuple) or isinstance(node, ast.List): [self.traverse_tuples(n, state + (i,), renamings) for i, n in enumerate(node.elts)] elif isinstance(node, (ast.Subscript, ast.Attribute)): if state: renamings[node] = state self.update = True else: raise NotImplementedError def visit_comprehension(self, node): node = self.generic_visit(node) renamings = OrderedDict() self.traverse_tuples(node.target, (), renamings) if renamings: self.update = True return self.get_new_id(), renamings else: return node def visit_AnyComp(self, node, *fields): for field in fields: setattr(node, field, self.visit(getattr(node, field))) generators = [self.visit(generator) for generator in node.generators] nnode = node for i, g in enumerate(generators): if isinstance(g, tuple): gtarget = "{0}{1}".format(g[0], i) nnode.generators[i].target = ast.Name( gtarget, nnode.generators[i].target.ctx, None, None) nnode = ConvertToTuple(gtarget, g[1]).visit(nnode) self.update = True for field in fields: setattr(node, field, getattr(nnode, field)) node.generators = nnode.generators return node def visit_ListComp(self, node): return self.visit_AnyComp(node, 'elt') def visit_SetComp(self, node): return self.visit_AnyComp(node, 'elt') def visit_DictComp(self, node): return self.visit_AnyComp(node, 'key', 'value') def visit_GeneratorExp(self, node): return self.visit_AnyComp(node, 'elt') def visit_Lambda(self, node): self.generic_visit(node) for i, arg in enumerate(node.args.args): renamings = OrderedDict() self.traverse_tuples(arg, (), renamings) if renamings: nname = self.get_new_id() node.args.args[i] = ast.Name(nname, ast.Param(), None, None) node.body = ConvertToTuple(nname, renamings).visit(node.body) return node def visit_Assign(self, node): self.generic_visit(node) # if the rhs is an identifier, we don't need to duplicate it # otherwise, better duplicate it... no_tmp = isinstance(node.value, (ast.Name, ast.Attribute)) extra_assign = [] if no_tmp else [node] for i, t in enumerate(node.targets): if isinstance(t, ast.Tuple) or isinstance(t, ast.List): renamings = OrderedDict() self.traverse_tuples(t, (), renamings) if renamings: if no_tmp: gstore = deepcopy(node.value) else: gstore = ast.Name(self.get_new_id(), ast.Store(), None, None) gload = deepcopy(gstore) gload.ctx = ast.Load() node.targets[i] = gstore for rename, state in renamings.items(): nnode = reduce( lambda x, y: ast.Subscript( x, ast.Constant(y, None), ast.Load()), state, gload) if isinstance(rename, str): extra_assign.append( ast.Assign( [ast.Name(rename, ast.Store(), None, None)], nnode, None)) else: extra_assign.append(ast.Assign([rename], nnode, None)) return extra_assign or node def visit_For(self, node): target = node.target if isinstance(target, ast.Tuple) or isinstance(target, ast.List): renamings = OrderedDict() self.traverse_tuples(target, (), renamings) if renamings: gtarget = self.get_new_id() node.target = ast.Name(gtarget, node.target.ctx, None, None) for rename, state in renamings.items(): nnode = reduce( lambda x, y: ast.Subscript( x, ast.Constant(y, None), ast.Load()), state, ast.Name(gtarget, ast.Load(), None, None)) if isinstance(rename, str): node.body.insert(0, ast.Assign( [ast.Name(rename, ast.Store(), None, None)], nnode, None) ) else: node.body.insert(0, ast.Assign([rename], nnode, None)) self.generic_visit(node) return node def visit_FunctionDef(self, node): self.ids = self.gather(Identifiers, node) return self.generic_visit(node)