def visit_UnaryOp(self, node): """ Update range with given unary operation. >>> import ast >>> from pythran import passmanager, backend >>> node = ast.parse(''' ... def foo(): ... a = 2 ... c = -a ... d = ~a ... f = +a ... e = not a''') >>> pm = passmanager.PassManager("test") >>> res = pm.gather(RangeValues, node) >>> res['f'] Range(low=2, high=2) >>> res['c'] Range(low=-2, high=-2) >>> res['d'] Range(low=-3, high=-3) >>> res['e'] Range(low=0, high=1) """ res = self.visit(node.operand) if isinstance(node.op, ast.Not): return Range(0, 1) elif (isinstance(node.op, ast.Invert) and isinstance(res.high, int) and isinstance(res.low, int)): return Range(~res.high, ~res.low) elif isinstance(node.op, ast.UAdd): return res elif isinstance(node.op, ast.USub): return Range(-res.high, -res.low) else: return UNKNOWN_RANGE
def visit_Compare(node): """ Boolean are possible index. >>> import ast >>> from pythran import passmanager, backend >>> node = ast.parse(''' ... def foo(): ... a = 2 or 3 ... b = 4 or 5 ... c = a < b''') >>> pm = passmanager.PassManager("test") >>> res = pm.gather(RangeValues, node) >>> res['c'] Range(low=0, high=1) """ return Range(0, 1)
def visit_BoolOp(self, node): """ Merge right and left operands ranges. TODO : We could exclude some operand with this range information... >>> import ast >>> from pythran import passmanager, backend >>> node = ast.parse(''' ... def foo(): ... a = 2 ... c = 3 ... d = a or c''') >>> pm = passmanager.PassManager("test") >>> res = pm.gather(RangeValues, node) >>> res['d'] Range(low=2, high=3) """ res = zip(*map(self.visit, node.values)) return Range(min(res[0]), max(res[1]))
def visit_IfExp(self, node): """ Use worst case for both possible values. >>> import ast >>> from pythran import passmanager, backend >>> node = ast.parse(''' ... def foo(): ... a = 2 or 3 ... b = 4 or 5 ... c = a if a else b''') >>> pm = passmanager.PassManager("test") >>> res = pm.gather(RangeValues, node) >>> res['c'] Range(low=2, high=5) """ self.visit(node.test) body_res = self.visit(node.body) orelse_res = self.visit(node.orelse) return Range(min(orelse_res.low, body_res.low), max(orelse_res.high, body_res.high))
def visit_Num(node): """ Handle literals integers values. """ if isinstance(node.n, int): return Range(node.n, node.n) else: return UNKNOWN_RANGE