class TupleListPattern(Pattern): # __builtin__.tuple(__builtin__.list(X)) => __builtin__.tuple(X) pattern = ast.Call( func=ast.Attribute(value=ast.Name('__builtin__', ast.Load(), None, None), attr="tuple", ctx=ast.Load()), args=[ ast.Call(func=ast.Attribute(value=ast.Name('__builtin__', ast.Load(), None, None), attr="list", ctx=ast.Load()), args=[Placeholder(0)], keywords=[]) ], keywords=[]) @staticmethod def sub(): return ast.Call(func=ast.Attribute(value=ast.Name(id='__builtin__', ctx=ast.Load(), annotation=None, type_comment=None), attr="tuple", ctx=ast.Load()), args=[Placeholder(0)], keywords=[])
class ReversedRangePattern(Pattern): # __builtin__.reversed(__builtin__.xrange(X)) => # __builtin__.xrange(X-1, -1, -1) # FIXME : We should do it even when begin/end/step are given pattern = ast.Call(func=ast.Attribute(value=ast.Name(id='__builtin__', ctx=ast.Load(), annotation=None, type_comment=None), attr="reversed", ctx=ast.Load()), args=[ast.Call( func=ast.Attribute( value=ast.Name(id='__builtin__', ctx=ast.Load(), annotation=None, type_comment=None), attr=range_name, ctx=ast.Load()), args=[Placeholder(0)], keywords=[])], keywords=[]) @staticmethod def sub(): return ast.Call( func=ast.Attribute(value=ast.Name(id='__builtin__', ctx=ast.Load(), annotation=None, type_comment=None), attr=range_name, ctx=ast.Load()), args=[ast.BinOp(left=Placeholder(0), op=ast.Sub(), right=ast.Constant(1, None)), ast.Constant(-1, None), ast.Constant(-1, None)], keywords=[])
class AbsSqrPattern(Pattern): # __builtin__.abs(X) ** 2 => __builtin__.pythran.abssqr(X) pattern = ast.Call(func=ast.Attribute(value=ast.Name(id=mangle('numpy'), ctx=ast.Load(), annotation=None, type_comment=None), attr="square", ctx=ast.Load()), args=[ ast.Call(func=ast.Attribute(value=ast.Name( id='__builtin__', ctx=ast.Load(), annotation=None, type_comment=None), attr="abs", ctx=ast.Load()), args=[Placeholder(0)], keywords=[]) ], keywords=[]) @staticmethod def sub(): return ast.Call(func=ast.Attribute(value=ast.Attribute(value=ast.Name( id='__builtin__', ctx=ast.Load(), annotation=None, type_comment=None), attr="pythran", ctx=ast.Load()), attr="abssqr", ctx=ast.Load()), args=[Placeholder(0)], keywords=[])
def dtype_to_ast(name): if name in ('bool', ): return ast.Attribute(ast.Name('__builtin__', ast.Load(), None, None), name, ast.Load()) else: return ast.Attribute(ast.Name(mangle('numpy'), ast.Load(), None, None), name, ast.Load())
def size_container_folding(value): """ Convert value to ast expression if size is not too big. Converter for sized container. """ if len(value) < MAX_LEN: if isinstance(value, list): return ast.List([to_ast(elt) for elt in value], ast.Load()) elif isinstance(value, tuple): return ast.Tuple([to_ast(elt) for elt in value], ast.Load()) elif isinstance(value, set): return ast.Set([to_ast(elt) for elt in value]) elif isinstance(value, dict): keys = [to_ast(elt) for elt in value.keys()] values = [to_ast(elt) for elt in value.values()] return ast.Dict(keys, values) elif isinstance(value, numpy.ndarray): return ast.Call( func=ast.Attribute(ast.Name(mangle('numpy'), ast.Load(), None), 'array', ast.Load()), args=[ to_ast(value.tolist()), ast.Attribute(ast.Name(mangle('numpy'), ast.Load(), None), value.dtype.name, ast.Load()) ], keywords=[]) else: raise ConversionError() else: raise ToNotEval()
def to_ast(value): """ Turn a value into ast expression. >>> a = 1 >>> print(ast.dump(to_ast(a))) Num(n=1) >>> a = [1, 2, 3] >>> print(ast.dump(to_ast(a))) List(elts=[Num(n=1), Num(n=2), Num(n=3)], ctx=Load()) """ if any(value is t for t in (bool, int, float)): iinfo = np.iinfo(int) if isinstance(value, int) and not (iinfo.min <= value <= iinfo.max): from pythran.syntax import PythranSyntaxError raise PythranSyntaxError("constant folding results in big int") return builtin_folding(value) elif isinstance(value, np.generic): return to_ast(value.item()) elif isinstance(value, (numbers.Number, str, bool, type(None))): return ast.Constant(value, None) elif isinstance(value, (list, tuple, set, dict, np.ndarray)): return size_container_folding(value) elif hasattr(value, "__module__") and value.__module__ == "builtins": # TODO Can be done the same way for others modules return builtin_folding(value) # only meaningful for python3 elif isinstance(value, (filter, map, zip)): return to_ast(list(value)) elif isinstance(value, np._globals._NoValueType): return ast.Attribute( ast.Attribute(ast.Name('numpy', ast.Load(), None, None), '_globals', ast.Load()), '_NoValueType', ast.Load()) raise ToNotEval()
def to_static_ast(node, class_node): assert isinstance(node, gast.Call) assert isinstance(class_node, gast.Call) static_api = to_static_api(class_node.func.attr) node.func = gast.Attribute(attr=static_api, ctx=gast.Load(), value=gast.Attribute(attr='layers', ctx=gast.Load(), value=gast.Name( ctx=gast.Load(), id='fluid', annotation=None, type_comment=None))) update_args_of_func(node, class_node, 'forward') node.args.extend(class_node.args) node.keywords.extend(class_node.keywords) _add_keywords_to(node, class_node.func.attr) _delete_keywords_from(node) gast.fix_missing_locations(node) return node
class LenRangePattern(Pattern): # builtins.len(builtins.range(X)) => max(0, X) pattern = ast.Call( func=ast.Attribute(value=ast.Name('builtins', ast.Load(), None, None), attr="len", ctx=ast.Load()), args=[ ast.Call(func=ast.Attribute(value=ast.Name('builtins', ast.Load(), None, None), attr="range", ctx=ast.Load()), args=[Placeholder(0)], keywords=[]) ], keywords=[]) @staticmethod def sub(): return ast.Call(func=ast.Attribute(value=ast.Name( 'builtins', ast.Load(), None, None), attr="max", ctx=ast.Load()), args=[ast.Constant(0, None), Placeholder(0)], keywords=[])
class LenSetPattern(Pattern): # __builtin__.len(__builtin__.set(X)) => __builtin__.pythran.len_set(X) pattern = ast.Call( func=ast.Attribute(value=ast.Name('__builtin__', ast.Load(), None, None), attr="len", ctx=ast.Load()), args=[ ast.Call(func=ast.Attribute(value=ast.Name('__builtin__', ast.Load(), None, None), attr="set", ctx=ast.Load()), args=[Placeholder(0)], keywords=[]) ], keywords=[]) @staticmethod def sub(): return ast.Call(func=ast.Attribute(value=ast.Attribute(value=ast.Name( '__builtin__', ast.Load(), None, None), attr="pythran", ctx=ast.Load()), attr="len_set", ctx=ast.Load()), args=[Placeholder(0)], keywords=[])
def visit_loop(self, node, update_mask=gast.NameConstant(value=None)): node = FuseAttributes().visit(node) loads, stores = defaultdict(list), set() for child in node.body: for n in gast.walk(child): if isinstance(n, gast.Name) and isinstance(n.ctx, gast.Load): loads[n.id].append(n) if isinstance(child, gast.Assign): if len(child.targets) > 1: raise NotImplementedError("cannot process LCD that is " "part of multiple assignment") name = child.targets[0].id if name in loads: if name in stores: raise NotImplementedError("cannot process LCD " "stored to twice") # $var = $expr -> $var = $var._update($expr) child.value = gast.Call( gast.Attribute(gast.Name(name, gast.Load(), None), gast.Name('_update', gast.Load(), None), None), [child.value, update_mask], []) stores.add(name) node = SplitAttributes().visit(node) synchronizes = [] for name in stores: synchronize = gast.Assign( [gast.Name(name, gast.Store(), None)], gast.Call( gast.Attribute( gast.Name(name, gast.Load(), None), gast.Name('_synchronize', gast.Load(), None), None), [], [])) synchronizes.append(synchronize) node.body.extend(synchronizes) return node
def visit_Lambda(self, node): op = issimpleoperator(node) if op is not None: if mangle('operator') not in self.global_declarations: import_ = ast.Import( [ast.alias('operator', mangle('operator'))]) self.imports.append(import_) operator_module = MODULES['operator'] self.global_declarations[mangle('operator')] = operator_module return ast.Attribute( ast.Name(mangle('operator'), ast.Load(), None, None), op, ast.Load()) self.generic_visit(node) forged_name = "{0}_lambda{1}".format(self.prefix, len(self.lambda_functions)) ii = self.gather(ImportedIds, node) ii.difference_update(self.lambda_functions) # remove current lambdas binded_args = [ ast.Name(iin, ast.Load(), None, None) for iin in sorted(ii) ] node.args.args = ( [ast.Name(iin, ast.Param(), None, None) for iin in sorted(ii)] + node.args.args) for patternname, pattern in self.patterns.items(): if issamelambda(pattern, node): proxy_call = ast.Name(patternname, ast.Load(), None, None) break else: duc = ExtendedDefUseChains() nodepattern = deepcopy(node) duc.visit(ast.Module([ast.Expr(nodepattern)], [])) self.patterns[forged_name] = nodepattern, duc forged_fdef = ast.FunctionDef(forged_name, copy(node.args), [ast.Return(node.body)], [], None, None) metadata.add(forged_fdef, metadata.Local()) self.lambda_functions.append(forged_fdef) self.global_declarations[forged_name] = forged_fdef proxy_call = ast.Name(forged_name, ast.Load(), None, None) if binded_args: if MODULES['functools'] not in self.global_declarations.values(): import_ = ast.Import( [ast.alias('functools', mangle('functools'))]) self.imports.append(import_) functools_module = MODULES['functools'] self.global_declarations[mangle( 'functools')] = functools_module return ast.Call( ast.Attribute( ast.Name(mangle('functools'), ast.Load(), None, None), "partial", ast.Load()), [proxy_call] + binded_args, []) else: return proxy_call
def handle_keywords(self, func, node, offset=0): ''' Gather keywords to positional argument information Assumes the named parameter exist, raises a KeyError otherwise ''' func_argument_names = {} for i, arg in enumerate(func.args.args[offset:]): assert isinstance(arg, ast.Name) func_argument_names[arg.id] = i func_argument_kwonly_names = {} for i, arg in enumerate(func.args.kwonlyargs): assert isinstance(arg, ast.Name) func_argument_kwonly_names[arg.id] = i nargs = len(func.args.args) - offset defaults = func.args.defaults keywords = {func_argument_names[kw.arg]: kw.value for kw in node.keywords if kw.arg not in func_argument_kwonly_names} keywords_only = [] nb_kw = len(node.keywords) for i, kw in enumerate(list(reversed(node.keywords))): if kw.arg in func_argument_kwonly_names: keywords_only.append((func_argument_kwonly_names[kw.arg], kw.value)) node.keywords.pop(nb_kw - i - 1) keywords_only = [v for _, v in sorted(keywords_only)] extra_keyword_offset = max(keywords.keys()) if keywords else 0 node.args.extend([None] * (1 + extra_keyword_offset - len(node.args))) replacements = {} for index, arg in enumerate(node.args): if arg is None: if index in keywords: replacements[index] = deepcopy(keywords[index]) else: # must be a default value replacements[index] = deepcopy(defaults[index - nargs]) if not keywords_only: return replacements node.args.append(ast.Call( ast.Attribute( ast.Attribute( ast.Name("builtins", ast.Load(), None, None), "pythran", ast.Load()), "kwonly", ast.Load()), [], []) ) node.args.extend(keywords_only) return replacements
def sub(): return ast.Call( func=ast.Attribute( value=ast.Attribute(value=ast.Name('__builtin__', ast.Load(), None, None), attr="pythran", ctx=ast.Load()), attr="len_set", ctx=ast.Load()), args=[Placeholder(0)], keywords=[])
def visit_Assign(self, node): if len(node.targets) > 1: raise NotImplementedError("cannot process multiple assignment") if not isinstance(node.targets[0], gast.Name): raise NotImplementedError("cannot process indexed assignment") # $lhs = $lhs.update_($rhs, matchbox.EXECUTION_MASK) if (lhs in vars() # or lhs in globals()) and isinstance($lhs, (matchbox.MaskedBatch, # matchbox.TENSOR_TYPE)) else $rhs node.value = gast.IfExp( gast.BoolOp( gast.And(), [ gast.BoolOp(gast.Or(), [ gast.Compare(gast.Str( node.targets[0].id), [gast.In()], [ gast.Call(gast.Name('vars', gast.Load, None), [], []) ]), gast.Compare(gast.Str( node.targets[0].id), [gast.In()], [ gast.Call( gast.Name('globals', gast.Load, None), [], []) ]) ]), # gast.Compare( # gast.Attribute( # gast.Name('matchbox', gast.Load(), None), # gast.Name('EXECUTION_MASK', gast.Load(), None), # gast.Load()), # [gast.IsNot()], # [gast.NameConstant(None)]), gast.Call(gast.Name('isinstance', gast.Load(), None), [ node.targets[0], gast.Tuple([ gast.Attribute( gast.Name('matchbox', gast.Load(), None), gast.Name('MaskedBatch', gast.Load(), None), gast.Load()), gast.Attribute( gast.Name('matchbox', gast.Load(), None), gast.Name('TENSOR_TYPE', gast.Load(), None), gast.Load()) ], gast.Load()) ], []) ]), gast.Call( gast.Attribute( gast.Name(node.targets[0].id, gast.Load(), None), gast.Name('_update', gast.Load(), None), gast.Load()), [ node.value, gast.Attribute( gast.Name('matchbox', gast.Load(), None), gast.Name('EXECUTION_MASK', gast.Load(), None), gast.Load()) ], []), node.value) return node
def visit_Attribute(self, node): node = self.generic_visit(node) # method name -> not a getattr if node.attr in methods: # Make sure parent is'nt a call, it's already handled in visit_Call for parent in reversed(self.ancestors.get(node, ())): if isinstance(parent, ast.Attribute): continue if isinstance(parent, ast.Call): return node break # we have a bound method which is not a call obj = self.baseobj(node) if obj is not None: self.update = True mod = methods[node.attr][0] self.to_import.add(mangle(mod[0])) func = self.attr_to_func(node) z = ast.Call( ast.Attribute( ast.Name(mangle('functools'), ast.Load(), None, None), "partial", ast.Load()), [func, obj], []) return z else: return node # imported module -> not a getattr elif (isinstance(node.value, ast.Name) and node.value.id in self.imports): module_id = self.imports[node.value.id] if node.attr not in MODULES[self.renamer(module_id, MODULES)[1]]: msg = ("`" + node.attr + "' is not a member of " + demangle(module_id) + " or Pythran does not support it") raise PythranSyntaxError(msg, node) node.value.id = module_id # patch module aliasing self.update = True return node # not listed as attributed -> not a getattr elif node.attr not in attributes: return node # A getattr ! else: self.update = True call = ast.Call( ast.Attribute(ast.Name('builtins', ast.Load(), None, None), 'getattr', ast.Load()), [node.value, ast.Constant(node.attr, None)], []) if isinstance(node.ctx, ast.Store): # the only situation where this arises is for real/imag of # a ndarray. As a call is not valid for a store, add a slice # to ends up with a valid lhs assert node.attr in ('real', 'imag'), "only store to imag/real" return ast.Subscript(call, ast.Slice(None, None, None), node.ctx) else: return call
def sub(): return ast.Call(func=ast.Attribute(value=ast.Attribute(value=ast.Name( id='builtins', ctx=ast.Load(), annotation=None, type_comment=None), attr="pythran", ctx=ast.Load()), attr="abssqr", ctx=ast.Load()), args=[Placeholder(0)], keywords=[])
def sub(): return ast.Call( func=ast.Attribute( ast.Attribute(ast.Name('__builtin__', ast.Load(), None, None), 'str', ast.Load()), 'join', ast.Load()), args=[ ast.Constant(Placeholder(1), None), ast.Tuple([Placeholder(0), Placeholder(2)], ast.Load()) ], keywords=[])
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
def makeattr(*args): r = ast.Attribute(value=ast.Name(id='__builtin__', ctx=ast.Load(), annotation=None), attr='map', ctx=ast.Load()) r = ast.Call(r, list(args), []) if sys.version_info.major == 3: r = ast.Call( ast.Attribute(ast.Name('__builtin__', ast.Load(), None), 'list', ast.Load()), [r], []) return r
def visit_Return(self, node): if node is self.guard: holder = "StaticIfNoReturn" else: holder = "StaticIfReturn" return ast.Return( ast.Call( ast.Attribute( ast.Attribute(ast.Name("__builtin__", ast.Load(), None), "pythran", ast.Load()), holder, ast.Load()), [node.value], []))
def visit_Return(self, node): if node is self.guard: holder = "StaticIfNoReturn" else: holder = "StaticIfReturn" value = node.value return ast.Return( ast.Call( ast.Attribute( ast.Attribute(ast.Name("builtins", ast.Load(), None, None), "pythran", ast.Load()), holder, ast.Load()), [value] if value else [ast.Constant(None, None)], []))
def size_container_folding(value): """ Convert value to ast expression if size is not too big. Converter for sized container. """ def size(x): return len(getattr(x, 'flatten', lambda: x)()) if size(value) < MAX_LEN: if isinstance(value, list): return ast.List([to_ast(elt) for elt in value], ast.Load()) elif isinstance(value, tuple): return ast.Tuple([to_ast(elt) for elt in value], ast.Load()) elif isinstance(value, set): if value: return ast.Set([to_ast(elt) for elt in value]) else: return ast.Call(func=ast.Attribute( ast.Name(mangle('builtins'), ast.Load(), None, None), 'set', ast.Load()), args=[], keywords=[]) elif isinstance(value, dict): keys = [to_ast(elt) for elt in value.keys()] values = [to_ast(elt) for elt in value.values()] return ast.Dict(keys, values) elif isinstance(value, np.ndarray): if len(value) == 0: return ast.Call( func=ast.Attribute( ast.Name(mangle('numpy'), ast.Load(), None, None), 'empty', ast.Load()), args=[to_ast(value.shape), dtype_to_ast(value.dtype.name)], keywords=[]) else: return ast.Call(func=ast.Attribute( ast.Name(mangle('numpy'), ast.Load(), None, None), 'array', ast.Load()), args=[ to_ast(totuple(value.tolist())), dtype_to_ast(value.dtype.name) ], keywords=[]) else: raise ConversionError() else: raise ToNotEval()
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() ), [], [],) ) 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_Compare(self, node): self.generic_visit(node) noned_var, negated = self.match_is_none(node) if noned_var is None: return node call = ast.Call( ast.Attribute( ast.Attribute(ast.Name('__builtin__', ast.Load(), None), 'pythran', ast.Load()), 'is_none', ast.Load()), [noned_var], []) if negated: return ast.UnaryOp(ast.Not(), call) else: return call
def visit_Raise(self, node): ntype = self._visit(node.type) ninst = self._visit(node.inst) ntback = self._visit(node.tback) what = ntype if ninst is not None: what = gast.Call(ntype, [ninst], []) gast.copy_location(what, node) what.end_lineno = what.end_col_offset = None if ntback is not None: attr = gast.Attribute(what, 'with_traceback', gast.Load()) gast.copy_location(attr, node) attr.end_lineno = attr.end_col_offset = None what = gast.Call(attr, [ntback], []) gast.copy_location(what, node) what.end_lineno = what.end_col_offset = None new_node = gast.Raise(what, None) gast.copy_location(new_node, node) new_node.end_lineno = new_node.end_col_offset = None return new_node
def visit_Attribute(self, node): node = self.generic_visit(node) # storing in an attribute -> not a getattr if not isinstance(node.ctx, ast.Load): return node # method name -> not a getattr elif node.attr in methods: return node # imported module -> not a getattr elif (isinstance(node.value, ast.Name) and node.value.id in self.imports): module_id = self.imports[node.value.id] if node.attr not in MODULES[self.renamer(module_id, MODULES)[1]]: msg = ("`" + node.attr + "' is not a member of " + module_id + " or Pythran does not support it") raise PythranSyntaxError(msg, node) node.value.id = module_id # patch module aliasing self.update = True return node # not listed as attributed -> not a getattr elif node.attr not in attributes: return node # A getattr ! else: self.update = True return ast.Call( ast.Attribute(ast.Name('__builtin__', ast.Load(), None), 'getattr', ast.Load()), [node.value, ast.Str(node.attr)], [])
def visit_BinOp(self, node): # replace "str" % (...) by __builtin__.str.__mod__(...) # the reason why we do this is that % formatting is handled by # a third party library that's relatively costly to load, so using a # function name instead of an operator overload makes it possible to # load it only when needed. The drawback is that % formatting is no # longer supported when lhs is not a literal self.generic_visit(node) if isinstance(node.op, ast.Mod) and isinstance(node.left, ast.Str): self.update = True return ast.Call( ast.Attribute( ast.Attribute(ast.Name('__builtin__', ast.Load(), None), 'str', ast.Load()), '__mod__', ast.Load()), [node.left, node.right], []) return node
def visit_Attribute(self, node): node = self.generic_visit(node) # method name -> not a getattr if node.attr in methods: return node # imported module -> not a getattr elif (isinstance(node.value, ast.Name) and node.value.id in self.imports): module_id = self.imports[node.value.id] if node.attr not in MODULES[self.renamer(module_id, MODULES)[1]]: msg = ("`" + node.attr + "' is not a member of " + module_id + " or Pythran does not support it") raise PythranSyntaxError(msg, node) node.value.id = module_id # patch module aliasing self.update = True return node # not listed as attributed -> not a getattr elif node.attr not in attributes: return node # A getattr ! else: self.update = True call = ast.Call( ast.Attribute(ast.Name('builtins', ast.Load(), None, None), 'getattr', ast.Load()), [node.value, ast.Constant(node.attr, None)], []) if isinstance(node.ctx, ast.Store): # the only situation where this arises is for real/imag of # a ndarray. As a call is not valid for a store, add a slice # to ends up with a valid lhs assert node.attr in ('real', 'imag'), "only store to imag/real" return ast.Subscript(call, ast.Slice(None, None, None), node.ctx) else: return call
def can_use_c_for(self, node): """ Check if a for loop can use classic C syntax. To use C syntax: - target should not be assign in the loop - range should be use as iterator - order have to be known at compile time """ assert isinstance(node.target, ast.Name) pattern_range = ast.Call(func=ast.Attribute(value=ast.Name( 'builtins', ast.Load(), None, None), attr='range', ctx=ast.Load()), args=AST_any(), keywords=[]) is_assigned = set() for stmt in node.body: is_assigned.update({n.id for n in self.gather(IsAssigned, stmt)}) nodes = ASTMatcher(pattern_range).search(node.iter) if node.iter not in nodes or node.target.id in is_assigned: return False args = node.iter.args if len(args) < 3: return True if isnum(args[2]): return True return False
def can_use_c_for(self, node): """ Check if a for loop can use classic C syntax. To use C syntax: - target should not be assign in the loop - xrange should be use as iterator - order have to be known at compile time """ assert isinstance(node.target, ast.Name) pattern = ast.Call(func=ast.Attribute(value=ast.Name(id='__builtin__', ctx=ast.Load(), annotation=None), attr='xrange', ctx=ast.Load()), args=AST_any(), keywords=[]) is_assigned = {node.target.id: False} [ is_assigned.update(self.passmanager.gather(IsAssigned, stmt)) for stmt in node.body ] if (node.iter not in ASTMatcher(pattern).search(node.iter) or is_assigned[node.target.id]): return False args = node.iter.args if len(args) < 3: return True if isinstance(args[2], ast.Num): return True return False