Пример #1
0
    def visit_UnaryOp(self, node):
        """ Update range with given unary operation.

        >>> import gast as 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']
        Interval(low=2, high=2)
        >>> res['c']
        Interval(low=-2, high=-2)
        >>> res['d']
        Interval(low=-3, high=-3)
        >>> res['e']
        Interval(low=0, high=1)
        """
        res = self.visit(node.operand)
        if isinstance(node.op, ast.Not):
            return Interval(0, 1)
        elif (isinstance(node.op, ast.Invert) and isinstance(res.high, int)
              and isinstance(res.low, int)):
            return Interval(~res.high, ~res.low)
        elif isinstance(node.op, ast.UAdd):
            return res
        elif isinstance(node.op, ast.USub):
            return Interval(-res.high, -res.low)
        else:
            return UNKNOWN_RANGE
Пример #2
0
    def visit_Compare(self, node):
        """ Boolean are possible index.

        >>> import gast as ast
        >>> from pythran import passmanager, backend
        >>> node = ast.parse('''
        ... def foo():
        ...     a = 2 or 3
        ...     b = 4 or 5
        ...     c = a < b
        ...     d = b < 3
        ...     e = b == 4''')
        >>> pm = passmanager.PassManager("test")
        >>> res = pm.gather(RangeValues, node)
        >>> res['c']
        Interval(low=1, high=1)
        >>> res['d']
        Interval(low=0, high=0)
        >>> res['e']
        Interval(low=0, high=1)
        """
        if any(
                isinstance(op, (ast.In, ast.NotIn, ast.Is, ast.IsNot))
                for op in node.ops):
            self.generic_visit(node)
            return self.add(node, Interval(0, 1))

        curr = self.visit(node.left)
        res = []
        for op, comparator in zip(node.ops, node.comparators):
            comparator = self.visit(comparator)
            fake = ast.Compare(ast.Name('x', ast.Load(), None), [op],
                               [ast.Name('y', ast.Load(), None)])
            fake = ast.Expression(fake)
            ast.fix_missing_locations(fake)
            expr = compile(ast.gast_to_ast(fake), '<range_values>', 'eval')
            res.append(eval(expr, {'x': curr, 'y': comparator}))
        if all(res):
            return self.add(node, Interval(1, 1))
        elif any(r.low == r.high == 0 for r in res):
            return self.add(node, Interval(0, 0))
        else:
            return self.add(node, Interval(0, 1))
Пример #3
0
    def visit_Compare(_):
        """ Boolean are possible index.

        >>> import gast as 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']
        Interval(low=0, high=1)
        """
        return Interval(0, 1)
Пример #4
0
    def visit_BoolOp(self, node):
        """ Merge right and left operands ranges.

        TODO : We could exclude some operand with this range information...

        >>> import gast as 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']
        Interval(low=2, high=3)
        """
        res = list(zip(*[self.visit(elt).bounds() for elt in node.values]))
        return self.add(node, Interval(min(res[0]), max(res[1])))
Пример #5
0
 def visit_Num(self, node):
     """ Handle literals integers values. """
     if isinstance(node.n, int):
         return self.add(node, Interval(node.n, node.n))
     return UNKNOWN_RANGE
Пример #6
0
 def visit_Constant(self, node):
     """ Handle literals integers values. """
     if isinstance(node.value, (bool, int)):
         return self.add(node, Interval(node.value, node.value))
     return UNKNOWN_RANGE
Пример #7
0
def bound_range(mapping, aliases, node, modified=None):
    """
    Bound the idenifier in `mapping' with the expression in `node'.
    `aliases' is the result of aliasing analysis and `modified' is
    updated with the set of identifiers possibly `bounded' as the result
    of the call.

    Returns `modified' or a fresh set of modified identifiers.

    """

    if modified is None:
        modified = set()

    if isinstance(node, ast.Name):
        # could be anything not just an integral
        pass

    elif isinstance(node, ast.UnaryOp):
        try:
            negated = negate(node.operand)
            bound_range(mapping, aliases, negated, modified)
        except UnsupportedExpression:
            pass

    elif isinstance(node, ast.BoolOp):
        if isinstance(node.op, ast.And):
            for value in node.values:
                bound_range(mapping, aliases, value, modified)
        elif isinstance(node.op, ast.Or):
            mappings = [mapping.copy() for _ in node.values]
            for value, mapping_cpy in zip(node.values, mappings):
                bound_range(mapping_cpy, aliases, value, modified)
            for k in modified:
                mapping[k] = reduce(lambda x, y: x.union(y[k]),
                                    mappings[1:],
                                    mappings[0][k])

    elif isinstance(node, ast.Compare):
        left = node.left
        if isinstance(node.left, ast.Name):
            modified.add(node.left.id)

        for op, right in zip(node.ops, node.comparators):
            if isinstance(right, ast.Name):
                modified.add(right.id)

            if isinstance(left, ast.Name):
                left_interval = mapping[left.id]
            else:
                left_interval = mapping[left]

            if isinstance(right, ast.Name):
                right_interval = mapping[right.id]
            else:
                right_interval = mapping[right]

            l_l, l_h = left_interval.low, left_interval.high
            r_l, r_h = right_interval.low, right_interval.high

            r_i = l_i = None

            if isinstance(op, ast.Eq):
                low, high = max(l_l, r_l), min(l_h, r_h)
                if low <= high:
                    l_i = r_i = Interval(max(l_l, r_l), min(l_h, r_h))
            elif isinstance(op, ast.Lt):
                # l < r => l.low < r.high & l.high < r.high
                l_i = Interval(min(l_l, r_h - 1), min(l_h, r_h - 1))
                # l < r => r.low < l.low & r.high < l.low
                r_i = Interval(max(r_l, l_l + 1), max(r_h, l_l + 1))
            elif isinstance(op, ast.LtE):
                # l <= r => l.low <= r.high & l.high <= r.high
                l_i = Interval(min(l_l, r_h), min(l_h, r_h))
                # l <= r => r.low <= l.low & r.high <= l.low
                r_i = Interval(max(r_l, l_l), max(r_h, l_l))
            elif isinstance(op, ast.Gt):
                # l > r => l.low > r.low & l.high > r.low
                l_i = Interval(max(l_l, r_l + 1), max(l_h, r_l + 1))
                # l > r => r.low > l.high & r.high > l.high
                r_i = Interval(min(r_l, l_h - 1), min(r_h, l_h - 1))
            elif isinstance(op, ast.GtE):
                # l >= r => l.high >= r.low & l.low >= r.low
                l_i = Interval(max(l_l, r_l), max(l_h, r_l))
                # l >= r => r.low > l.high & r.high >= l.high
                r_i = Interval(min(r_l, l_h), min(r_h, l_h))
            elif isinstance(op, ast.In):
                if isinstance(right, (ast.List, ast.Tuple, ast.Set)):
                    if right.elts:
                        low = min(mapping[elt].low for elt in right.elts)
                        high = max(mapping[elt].high for elt in right.elts)
                        l_i = Interval(low, high)
                elif isinstance(right, ast.Call):
                    for alias in aliases[right.func]:
                        if not hasattr(alias, 'return_range_content'):
                            l_i = None
                            break
                        rrc = alias.return_range_content([mapping[arg] for arg
                                                          in right.args])
                        if l_i is None:
                            l_i = rrc
                        else:
                            l_i = l_i.union(alias.return_range(right))

            if l_i is not None and isinstance(left, ast.Name):
                mapping[left.id] = l_i
            if r_i is not None and isinstance(right, ast.Name):
                mapping[right.id] = r_i

            left = right
Пример #8
0
 def visit_Num(node):
     """ Handle literals integers values. """
     if isinstance(node.n, int):
         return Interval(node.n, node.n)
     else:
         return UNKNOWN_RANGE