def visit_Compare(self, node): node = self.generic_visit(node) if len(node.ops) > 1: # in case we have more than one compare operator # we generate an auxiliary function # that lazily evaluates the needed parameters imported_ids = self.gather(ImportedIds, node) imported_ids = sorted(imported_ids) binded_args = [ast.Name(i, ast.Load(), None) for i in imported_ids] # name of the new function forged_name = "{0}_compare{1}".format(self.prefix, len(self.compare_functions)) # call site call = ast.Call( ast.Name(forged_name, ast.Load(), None), binded_args, []) # new function arg_names = [ast.Name(i, ast.Param(), None) for i in imported_ids] args = ast.arguments(arg_names, None, [], [], None, []) body = [] # iteratively fill the body (yeah, feel your body!) if is_trivially_copied(node.left): prev_holder = node.left else: body.append(ast.Assign([ast.Name('$0', ast.Store(), None)], node.left)) prev_holder = ast.Name('$0', ast.Load(), None) for i, exp in enumerate(node.comparators): if is_trivially_copied(exp): holder = exp else: body.append(ast.Assign([ast.Name('${}'.format(i+1), ast.Store(), None)], exp)) holder = ast.Name('${}'.format(i+1), ast.Load(), None) cond = ast.Compare(prev_holder, [node.ops[i]], [holder]) body.append(ast.If(cond, [ast.Pass()], [ast.Return(path_to_attr(('__builtin__', 'False')))])) prev_holder = holder body.append(ast.Return(path_to_attr(('__builtin__', 'True')))) forged_fdef = ast.FunctionDef(forged_name, args, body, [], None) self.compare_functions.append(forged_fdef) return call else: return node
def visit_Compare(self, node): node = self.generic_visit(node) if len(node.ops) > 1: # in case we have more than one compare operator # we generate an auxiliary function # that lazily evaluates the needed parameters imported_ids = self.passmanager.gather(ImportedIds, node, self.ctx) imported_ids = sorted(imported_ids) binded_args = [ast.Name(i, ast.Load(), None) for i in imported_ids] # name of the new function forged_name = "{0}_compare{1}".format(self.prefix, len(self.compare_functions)) # call site call = ast.Call(ast.Name(forged_name, ast.Load(), None), binded_args, []) # new function arg_names = [ast.Name(i, ast.Param(), None) for i in imported_ids] args = ast.arguments(arg_names, None, [], [], None, []) body = [] # iteratively fill the body (yeah, feel your body!) if is_trivially_copied(node.left): prev_holder = node.left else: body.append( ast.Assign([ast.Name('$0', ast.Store(), None)], node.left)) prev_holder = ast.Name('$0', ast.Load(), None) for i, exp in enumerate(node.comparators): if is_trivially_copied(exp): holder = exp else: body.append( ast.Assign( [ast.Name('${}'.format(i + 1), ast.Store(), None)], exp)) holder = ast.Name('${}'.format(i + 1), ast.Load(), None) cond = ast.Compare(prev_holder, [node.ops[i]], [holder]) body.append( ast.If( cond, [ast.Pass()], [ast.Return(path_to_attr(('__builtin__', 'False')))])) prev_holder = holder body.append(ast.Return(path_to_attr(('__builtin__', 'True')))) forged_fdef = ast.FunctionDef(forged_name, args, body, [], None) self.compare_functions.append(forged_fdef) return call else: return node
def inlineFixedSizeArrayCompare(self, node): if len(node.comparators) != 1: return node node_right = node.comparators[0] alike = ast.Num, ast.List, ast.Tuple if isinstance(node.left, alike) and isinstance(node_right, alike): return node lbase, lsize = self.fixedSizeArray(node.left) rbase, rsize = self.fixedSizeArray(node_right) if not lbase or not rbase: return node if rsize != 1 and lsize != 1 and rsize != lsize: raise PythranSyntaxError("Invalid numpy broadcasting", node) self.update = True operands = [ ast.Compare(self.make_array_index(lbase, lsize, i), [type(node.ops[0])()], [self.make_array_index(rbase, rsize, i)]) for i in range(max(lsize, rsize)) ] res = ast.Call(path_to_attr(('numpy', 'array')), [ast.Tuple(operands, ast.Load())], []) self.aliases[res.func] = {path_to_node(('numpy', 'array'))} return res
def visit_Name(self, node): """ Replace name with full expanded name. Examples -------- >> from numpy.linalg import det >> det(a) Becomes >> numpy.linalg.det(a) """ if node.id in self.symbols: symbol = path_to_node(self.symbols[node.id]) if not getattr(symbol, 'isliteral', lambda: False)(): parent = self.ancestors[node][-1] blacklist = (ast.Tuple, ast.List, ast.Set, ast.Return) if isinstance(parent, blacklist): raise PythranSyntaxError( "Unsupported module identifier manipulation", node) new_node = path_to_attr(self.symbols[node.id]) new_node.ctx = node.ctx ast.copy_location(new_node, node) return new_node return node
def visit_ListComp(self, node): def makeattr(*args): r = ast.Attribute(value=ast.Name(id='builtins', ctx=ast.Load(), annotation=None, type_comment=None), attr='map', ctx=ast.Load()) r = ast.Call(r, list(args), []) r = ast.Call( ast.Attribute(ast.Name('builtins', ast.Load(), None, None), 'list', ast.Load()), [r], []) return r if isinstance(node.elt, ast.Constant) and len(node.generators) == 1: gen = node.generators[0] if not gen.ifs and isinstance(gen.iter, ast.Call): try: path = attr_to_path(gen.iter.func)[1] range_path = 'pythonic', 'builtins', 'functor', 'range' if path == range_path and len(gen.iter.args) == 1: self.update = True return ast.BinOp( ast.List([node.elt], ast.Load()), ast.Mult(), ast.Call(path_to_attr(('builtins', 'len')), [gen.iter], [])) except TypeError: pass return self.visitComp(node, makeattr)
def inlineFixedSizeArrayBinOp(self, node): alike = ast.List, ast.Tuple, ast.Constant if isinstance(node.left, alike) and isinstance(node.right, alike): return node lbase, lsize = self.fixedSizeArray(node.left) rbase, rsize = self.fixedSizeArray(node.right) if not lbase or not rbase: return node if rsize != 1 and lsize != 1 and rsize != lsize: raise PythranSyntaxError("Invalid numpy broadcasting", node) self.update = True operands = [ ast.BinOp(self.make_array_index(lbase, lsize, i), type(node.op)(), self.make_array_index(rbase, rsize, i)) for i in range(max(lsize, rsize)) ] res = ast.Call(path_to_attr(('numpy', 'array')), [ast.Tuple(operands, ast.Load())], []) self.aliases[res.func] = {path_to_node(('numpy', 'array'))} return res
def visit_Call(self, node): """Replace function call by its correct iterator if it is possible.""" if node in self.potential_iterator: matched_path = self.find_matching_builtin(node) if matched_path is None: return self.generic_visit(node) # Special handling for map which can't be turn to imap with None as # a parameter as map(None, [1, 2]) == [1, 2] while # list(imap(None, [1, 2])) == [(1,), (2,)] if (matched_path[1] == "map" and MODULES["builtins"]["None"] in self.aliases[node.args[0]]): return self.generic_visit(node) # if a dtype conversion is implied if matched_path[1] in ('array', 'asarray') and len(node.args) != 1: return self.generic_visit(node) path = EQUIVALENT_ITERATORS[matched_path] if path: node.func = path_to_attr(path) self.use_itertools |= path[0] == 'itertools' else: node = node.args[0] self.update = True return self.generic_visit(node)
def inlineFixedSizeArrayCompare(self, node): if len(node.comparators) != 1: return node node_right = node.comparators[0] alike = ast.Num, ast.List, ast.Tuple if isinstance(node.left, alike) and isinstance(node_right, alike): return node lbase, lsize = self.fixedSizeArray(node.left) rbase, rsize = self.fixedSizeArray(node_right) if not lbase or not rbase: return node if rsize != 1 and lsize != 1 and rsize != lsize: raise PythranSyntaxError("Invalid numpy broadcasting", node) self.update = True operands = [ast.Compare(self.make_array_index(lbase, lsize, i), [type(node.ops[0])()], [self.make_array_index(rbase, rsize, i)]) for i in range(max(lsize, rsize))] res = ast.Call(path_to_attr(('numpy', 'array')), [ast.Tuple(operands, ast.Load())], []) self.aliases[res.func] = {path_to_node(('numpy', 'array'))} return res
def visit_Call(self, node): """ Replace function call by its correct iterator if it is possible.""" if node in self.potential_iterator: match_keyword = self.find_matching_builtin(node) if match_keyword: node.func = path_to_attr(EQUIVALENT_ITERATORS[match_keyword]) self.update = True return self.generic_visit(node)
def convert(self, node): self.update = True if isinstance(node, ast.Call): if not node.args: node = ast.Tuple([]) else: node = node.args[0] elif isinstance(node, ast.List): node = ast.Tuple(node.elts, ast.Load()) return ast.Call(path_to_attr(('__builtin__', 'pythran', 'static_list')), [node], [])
def visit_Call(self, node): """Replace function call by its correct iterator if it is possible.""" if node in self.potential_iterator: match_keyword = self.find_matching_builtin(node) # Special handling for map which can't be turn to imap with None as # a parameter as map(None, [1, 2]) == [1, 2] while # list(imap(None, [1, 2])) == [(1,), (2,)] if (match_keyword == "map" and MODULES["__builtin__"]["None"] in self.aliases[node.args[0]]): return self.generic_visit(node) if match_keyword: node.func = path_to_attr(EQUIVALENT_ITERATORS[match_keyword]) self.update = True return self.generic_visit(node)
def inlineFixedSizeArrayUnaryOp(self, node): if isinstance(node.operand, (ast.Num, ast.List, ast.Tuple)): return node base, size = self.fixedSizeArray(node.operand) if not base: return node self.update = True operands = [ ast.UnaryOp(type(node.op)(), self.make_array_index(base, size, i)) for i in range(size) ] res = ast.Call(path_to_attr(('numpy', 'array')), [ast.Tuple(operands, ast.Load())], []) self.aliases[res.func] = {path_to_node(('numpy', 'array'))} return res
def visit_Call(self, node): """Replace function call by its correct iterator if it is possible.""" if node in self.potential_iterator: matched_path = self.find_matching_builtin(node) if matched_path is None: return self.generic_visit(node) # if any kind of specific (~ with more arg) behavior is required if len(node.args) != 1: return self.generic_visit(node) path = EQUIVALENT_ITERATORS[matched_path] if path: node.func = path_to_attr(path) else: node = node.args[0] self.update = True return self.generic_visit(node)
def inlineFixedSizeArrayUnaryOp(self, node): if isinstance(node.operand, (ast.Num, ast.List, ast.Tuple)): return node base, size = self.fixedSizeArray(node.operand) if not base: return node self.update = True operands = [ast.UnaryOp(type(node.op)(), self.make_array_index(base, size, i)) for i in range(size)] res = ast.Call(path_to_attr(('numpy', 'array')), [ast.Tuple(operands, ast.Load())], []) self.aliases[res.func] = {path_to_node(('numpy', 'array'))} return res
def visit_Name(self, node): """ Replace name with full expanded name. Examples -------- >> from numpy.linalg import det >> det(a) Becomes >> numpy.linalg.det(a) """ if node.id in self.symbols: new_node = path_to_attr(self.symbols[node.id]) new_node.ctx = node.ctx ast.copy_location(new_node, node) return new_node return node
def visit_List(self, node): # because global lists in pythran are static lists return ast.Call( path_to_attr(('builtins', 'pythran', 'static_list')), [ast.Tuple([self.visit(elt) for elt in node.elts], ast.Load())], [])