Exemplo n.º 1
0
    def __init__(self,
                 variables: Set[VariableIdentifier],
                 precursory: State = None):
        """Map each program variable to the type representing its value.

        :param variables: set of program variables
        """
        lattices = defaultdict(lambda: TypeLattice)
        arguments = defaultdict(
            lambda: {'type_status': TypeLattice.Status.String})
        arguments[BooleanLyraType()] = {
            'type_status': TypeLattice.Status.Boolean
        }
        arguments[ListLyraType(BooleanLyraType())] = {
            'type_status': TypeLattice.Status.Boolean
        }
        arguments[IntegerLyraType()] = {
            'type_status': TypeLattice.Status.Integer
        }
        arguments[ListLyraType(IntegerLyraType())] = {
            'type_status': TypeLattice.Status.Integer
        }
        arguments[FloatLyraType()] = {'type_status': TypeLattice.Status.Float}
        arguments[ListLyraType(FloatLyraType())] = {
            'type_status': TypeLattice.Status.Float
        }

        super().__init__(variables, lattices, arguments)
        InputMixin.__init__(self, precursory)
Exemplo n.º 2
0
 def range_call_semantics(self, stmt: Call, state: State) -> State:
     result = set()
     if len(stmt.arguments) == 1:
         start = Literal(IntegerLyraType(), "0")
         stops = self.semantics(stmt.arguments[0], state).result
         step = Literal(IntegerLyraType(), "1")
         for stop in stops:
             range = Range(stmt.typ, start, stop, step)
             result.add(range)
         state.result = result
         return state
     elif len(stmt.arguments) == 2:
         starts = self.semantics(stmt.arguments[0], state).result
         stops = self.semantics(stmt.arguments[1], state).result
         step = Literal(IntegerLyraType(), "1")
         for start in starts:
             for stop in stops:
                 range = Range(stmt.typ, start, stop, step)
                 result.add(range)
         state.result = result
         return state
     elif len(stmt.arguments) == 3:
         starts = self.semantics(stmt.arguments[0], state).result
         stops = self.semantics(stmt.arguments[1], state).result
         steps = self.semantics(stmt.arguments[2], state).result
         for start in starts:
             for stop in stops:
                 for step in steps:
                     range = Range(stmt.typ, start, stop, step)
                     result.add(range)
         state.result = result
         return state
     error = f"Call to {stmt.name} with unexpected number of arguments!"
     raise ValueError(error)
Exemplo n.º 3
0
 def _join(self, other: InputLattice) -> InputLattice:   # TODO:
     """``Ɣ(self) ⋃ Ɣ(other) ⊆ Ɣ(self \/ other)``."""
     def do(constraint1, constraint2):
         if isinstance(constraint1, tuple) and isinstance(constraint2, tuple):
             # the constraints are StarConstraints or BasicConstraints
             if not constraint1 and not constraint2:
                 # the constraints are StarConstraints
                 return ()
             else:   # the constraints are BasicConstraints
                 pp1: ProgramPoint = constraint1[0]
                 pp2: ProgramPoint = constraint2[0]
                 pp: ProgramPoint = pp1 if pp1.line <= pp2.line else pp2
                 l1: Tuple[JSONMixin, ...] = constraint1[1]
                 l2: Tuple[JSONMixin, ...] = constraint2[1]
                 return pp, tuple(x.join(y) for x, y in zip(l1, l2))
         else:   # the constraints are InputLattices
             m1: Expression = constraint1.multiplier
             m2: Expression = constraint2.multiplier
             c1 = constraint1.constraints
             c2 = constraint2.constraints
             if isinstance(m1, Literal) and isinstance(m2, Literal):
                 assert isinstance(m1.typ, IntegerLyraType)
                 assert isinstance(m2.typ, IntegerLyraType)
                 val = str(min(int(m1.val), int(m2.val)))
                 m: Expression = Literal(IntegerLyraType(), val)
             else:
                 m: Expression = m1 if m1 == m2 else one
             r: bool = m1 != m2      # are the multipliers different?
             c = [do(x, y) for x, y in zip(c1, c2)]
             # do the list of constraints have different length?
             r = r or len(c1) != len(c2)
             if r:   # multipliers of lengths of list of constraints are different
                 c.append(())    # add a star constraint
             return AssumptionState.InputStack.InputLattice(m, c)
     multiplier1 = self.multiplier
     multiplier2 = other.multiplier
     assert isinstance(multiplier1, Literal) and multiplier1.val == "1"
     assert isinstance(multiplier2, Literal) and multiplier2.val == "1"
     if len(self.constraints) == len(other.constraints):
         constraints = [do(x, y) for x, y in zip(self.constraints, other.constraints)]
         one = Literal(IntegerLyraType(), "1")
         return self._replace(AssumptionState.InputStack.InputLattice(one, constraints))
     else:   # the join is happening at a loop head
         assert abs(len(self.constraints) - len(other.constraints)) == 1
         one = Literal(IntegerLyraType(), "1")
         if len(self.constraints) < len(other.constraints):
             tail = other.constraints[1:]
             constraints = [do(x, y) for x, y in zip(self.constraints, tail)]
             other.constraints[1:] = constraints
             join = AssumptionState.InputStack.InputLattice(one, other.constraints)
             self._replace(join)
         else:
             tail = self.constraints[1:]
             constraints = [do(x, y) for x, y in zip(tail, other.constraints)]
             self.constraints[1:] = constraints
             join = AssumptionState.InputStack.InputLattice(one, self.constraints)
             self._replace(join)
         return self
Exemplo n.º 4
0
 def visit_Call(self, node, types=None, typ=None):
     """Visitor function for a call.
     The attribute func stores the function being called (often a Name or Attribute object).
     The attribute args stores a list fo the arguments passed by position."""
     pp = ProgramPoint(node.lineno, node.col_offset)
     if isinstance(node.func, ast.Name):
         name: str = node.func.id
         if name == 'bool' or name == 'int':
             arguments = [self.visit(arg, types, typ) for arg in node.args]
             return Call(pp, name, arguments, typ)
         if name == 'input':
             arguments = [self.visit(arg, types, StringLyraType()) for arg in node.args]
             return Call(pp, name, arguments, StringLyraType())
         if name == 'range':
             arguments = [self.visit(arg, types, IntegerLyraType()) for arg in node.args]
             return Call(pp, name, arguments, ListLyraType(IntegerLyraType()))
         arguments = [self.visit(arg, types, None) for arg in node.args]
         return Call(pp, name, arguments, typ)
     elif isinstance(node.func, ast.Attribute):
         name: str = node.func.attr
         if name == 'append':
             arguments = [self.visit(node.func.value, types, None)]  # target of the call
             args = [self.visit(arg, types, None) for arg in node.args]
             arguments.extend(args)
             assert isinstance(arguments[0].typ, ListLyraType)
             return Call(pp, name, arguments, arguments[0].typ)
         if name == 'items':
             arguments = [self.visit(node.func.value, types, None)]  # target of the call
             args = [self.visit(arg, types, None) for arg in node.args]
             arguments.extend(args)
             assert isinstance(arguments[0].typ, DictLyraType)
             tuple_typ = TupleLyraType([arguments[0].typ.key_typ, arguments[0].typ.val_typ])
             return Call(pp, name, arguments, SetLyraType(tuple_typ))
         if name == 'keys':
             arguments = [self.visit(node.func.value, types, None)]  # target of the call
             args = [self.visit(arg, types, None) for arg in node.args]
             arguments.extend(args)
             assert isinstance(arguments[0].typ, DictLyraType)
             return Call(pp, name, arguments, SetLyraType(arguments[0].typ.key_typ))
         if name == 'split':     # str.split([sep[, maxsplit]])
             assert isinstance(typ, ListLyraType)    # we expect type to be a ListLyraType
             arguments = [self.visit(node.func.value, types, typ.typ)]   # target of the call
             args_typs = zip(node.args, [typ.typ, IntegerLyraType()])
             args = [self.visit(arg, types, arg_typ) for arg, arg_typ in args_typs]
             arguments.extend(args)
             return Call(pp, name, arguments, typ)
         if name == 'values':
             arguments = [self.visit(node.func.value, types, None)]  # target of the call
             args = [self.visit(arg, types, None) for arg in node.args]
             arguments.extend(args)
             assert isinstance(arguments[0].typ, DictLyraType)
             return Call(pp, name, arguments, SetLyraType(arguments[0].typ.val_typ))
         arguments = [self.visit(node.func.value, types, None)]   # target of the call
         arguments.extend([self.visit(arg, types, None) for arg in node.args])
         return Call(pp, name, arguments, typ)
Exemplo n.º 5
0
    def visit_For(self, node, types=None, typ=None):
        header_node = Loop(self._id_gen.next)

        cfg = self._translate_body(node.body, types, typ)
        body_in_node = cfg.in_node
        body_out_node = cfg.out_node

        pp = ProgramPoint(node.target.lineno, node.target.col_offset)
        iteration = self.visit(node.iter, types,
                               ListLyraType(IntegerLyraType()))
        if isinstance(iteration, Call) and iteration.name == "range":
            target_type = IntegerLyraType()
        else:
            error = f"The for loop iteration statment {node.iter} is not yet translatable to CFG!"
            raise NotImplementedError(error)
        target = self.visit(node.target, types, target_type)

        test = Call(pp, "in", [target, iteration], BooleanLyraType())
        neg_test = Call(pp, "not", [test], BooleanLyraType())

        cfg.add_node(header_node)
        cfg.in_node = header_node

        cfg.add_edge(
            Conditional(header_node, test, body_in_node, Edge.Kind.LOOP_IN))
        cfg.add_edge(Conditional(header_node, neg_test, None))
        if body_out_node:  # if control flow can exit the body at all, add an unconditional LOOP_OUT edge
            cfg.add_edge(
                Unconditional(body_out_node, header_node, Edge.Kind.LOOP_OUT))

        if node.orelse:  # if there is else branch
            orelse_cfg = self._translate_body(node.orelse, types)
            if orelse_cfg.out_node:  # if control flow can exit the else at all, add an unconditional DEFAULT edge
                orelse_cfg.add_edge(
                    Unconditional(orelse_cfg.out_node, None,
                                  Edge.Kind.DEFAULT))
            cfg.append(orelse_cfg)

        for special_edge, edge_type in cfg.special_edges:
            if edge_type == LooseControlFlowGraph.SpecialEdgeType.CONTINUE:
                cfg.add_edge(
                    Unconditional(special_edge.source, header_node,
                                  Edge.Kind.LOOP_OUT))
            elif edge_type == LooseControlFlowGraph.SpecialEdgeType.BREAK:
                cfg.add_edge(
                    Unconditional(special_edge.source, None,
                                  Edge.Kind.LOOP_OUT))
        cfg.special_edges.clear()

        return cfg
Exemplo n.º 6
0
 def __init__(self,
              multiplier: Expression = Literal(
                  IntegerLyraType(), "1"),
              constraints: List[InputConstraint] = list()):
     super().__init__()
     self._multiplier = multiplier
     self._constraints = constraints
Exemplo n.º 7
0
 def do(constraint1, constraint2):
     if isinstance(constraint1, tuple) and isinstance(constraint2, tuple):
         # the constraints are StarConstraints or BasicConstraints
         if not constraint1 and not constraint2:
             # the constraints are StarConstraints
             return ()
         else:   # the constraints are BasicConstraints
             pp1: ProgramPoint = constraint1[0]
             pp2: ProgramPoint = constraint2[0]
             pp: ProgramPoint = pp1 if pp1.line <= pp2.line else pp2
             l1: Tuple[JSONMixin, ...] = constraint1[1]
             l2: Tuple[JSONMixin, ...] = constraint2[1]
             return pp, tuple(x.join(y) for x, y in zip(l1, l2))
     else:   # the constraints are InputLattices
         m1: Expression = constraint1.multiplier
         m2: Expression = constraint2.multiplier
         c1 = constraint1.constraints
         c2 = constraint2.constraints
         if isinstance(m1, Literal) and isinstance(m2, Literal):
             assert isinstance(m1.typ, IntegerLyraType)
             assert isinstance(m2.typ, IntegerLyraType)
             val = str(min(int(m1.val), int(m2.val)))
             m: Expression = Literal(IntegerLyraType(), val)
         else:
             m: Expression = m1 if m1 == m2 else one
         r: bool = m1 != m2      # are the multipliers different?
         c = [do(x, y) for x, y in zip(c1, c2)]
         # do the list of constraints have different length?
         r = r or len(c1) != len(c2)
         if r:   # multipliers of lengths of list of constraints are different
             c.append(())    # add a star constraint
         return AssumptionState.InputStack.InputLattice(m, c)
Exemplo n.º 8
0
 def visit_Range(self, expr: Range, state=None):
     literal1 = isinstance(expr.start, Literal)
     literal2 = isinstance(expr.stop, Literal)
     variable2 = isinstance(expr.stop, VariableIdentifier)
     literal3 = isinstance(expr.step, Literal)
     if literal1 and literal2 and literal3:
         start = int(expr.start.val)
         stop = int(expr.stop.val)
         step = int(expr.step.val)
         length = len(range(start, stop, step))
         return state.lattices[IntegerLyraType()](lower=length, upper=length)
     elif literal1 and variable2 and literal3:
         start = int(expr.start.val)
         stop = state.store[expr.stop]
         return state.lattices[IntegerLyraType()](lower=start).meet(stop)
     raise ValueError(f"Unexpected expression during sequence length computation.")
Exemplo n.º 9
0
        def visit_Slicing(self, expr: Slicing, state=None):
            lattice: IntervalLattice = state.lattices[IntegerLyraType()]

            def is_one(stride):
                literal = isinstance(stride, Literal)
                return literal and lattice(stride).less_equal(lattice(lower=1, upper=1))

            if isinstance(expr.lower, Literal):
                lower = IntervalLattice.from_literal(expr.lower)
                if not lower.less_equal(lattice(lower=0)):
                    lower = lower.add(state.store[LengthIdentifier(expr.target)])
                if not expr.upper:
                    upper = deepcopy(state.store[LengthIdentifier(expr.target)])
                    if not expr.stride or is_one(expr.stride):  # [l:_:(1)]
                        length = lattice(lower=0).meet(upper.sub(lower))
                        if length.is_bottom():
                            return lattice(lower=0, upper=0)
                        return length
                elif isinstance(expr.upper, Literal):
                    upper = IntervalLattice.from_literal(expr.upper)
                    if not upper.less_equal(lattice(lower=0)):
                        upper = upper.add(state.store[LengthIdentifier(expr.target)])
                    if not expr.stride or is_one(expr.stride):  # [l:u:(1)]
                        length = lattice(lower=0).meet(upper.sub(lower))
                        if length.is_bottom():
                            return lattice(lower=0, upper=0)
                        return length
            return deepcopy(state.store[LengthIdentifier(expr.target)])   # over-approximation
Exemplo n.º 10
0
    def __init__(self, variable: VariableIdentifier):
        """Sequence or collection length construction.

        :param variable: sequence or collection the length of which is being constructed
        """
        name = "len({0.name})".format(variable)
        super().__init__(IntegerLyraType(), name)
Exemplo n.º 11
0
    def int_call_semantics(self, stmt: Call, state: State) -> State:
        """Semantics of a call to 'int'.

        :param stmt: call to 'int' to be executed
        :param state: state before executing the call statement
        :return: state modified by the call statement
        """
        return self._cast_call_semantics(stmt, state, IntegerLyraType())
Exemplo n.º 12
0
 def visit_Num(self, node, types=None, typ=None):
     pp = ProgramPoint(node.lineno, node.col_offset)
     if isinstance(node.n, int):
         expr = Literal(IntegerLyraType(), str(node.n))
         return LiteralEvaluation(pp, expr)
     elif isinstance(node.n, float):
         expr = Literal(FloatLyraType(), str(node.n))
         return LiteralEvaluation(pp, expr)
     raise NotImplementedError(f"Num {node.n.__class__.__name__} is not yet supported!")
Exemplo n.º 13
0
 def range_call_semantics(self, stmt: Call, state: State) -> State:
     arguments = [
         self.semantics(arg, state).result.pop() for arg in stmt.arguments
     ]
     start = Literal(IntegerLyraType(), "0")
     step = Literal(IntegerLyraType(), "1")
     if len(arguments) == 1:
         end = arguments[0]
     elif len(arguments) in [2, 3]:
         start = arguments[0]
         end = arguments[1]
         if len(arguments) == 3:
             step = arguments[2]
     else:
         error = f"Semantics for range call with {len(arguments)} arguments is not implemented!"
         raise NotImplementedError(error)
     state.result = {Range(stmt.typ, start, end, step)}
     return state
Exemplo n.º 14
0
            def _join(self, other: InputLattice) -> InputLattice:
                def do(constraint1, constraint2):
                    if isinstance(constraint1, tuple) and isinstance(
                            constraint2, tuple):
                        # the constraints are StarConstraints or BasicConstraints
                        if not constraint1 and not constraint2:
                            # the constraints are StarConstraints
                            return ()
                        else:  # the constraints are BasicConstraints
                            pp1: ProgramPoint = constraint1[0]
                            pp2: ProgramPoint = constraint2[0]
                            pp: ProgramPoint = pp1 if pp1.line <= pp2.line else pp2
                            l1: Tuple[JSONMixin, ...] = constraint1[1]
                            l2: Tuple[JSONMixin, ...] = constraint2[1]
                            return pp, tuple(x.join(y) for x, y in zip(l1, l2))
                    else:  # the constraints are InputLattices
                        assert isinstance(
                            constraint1,
                            AssumptionState.InputStack.InputLattice)
                        assert isinstance(
                            constraint2,
                            AssumptionState.InputStack.InputLattice)
                        m1: Expression = constraint1.multiplier
                        m2: Expression = constraint2.multiplier
                        c1 = constraint1.constraints
                        c2 = constraint2.constraints
                        is_one1 = isinstance(m1, Literal) and m1.val == "1"
                        is_one2 = isinstance(m2, Literal) and m2.val == "1"
                        if is_one1 and is_one2:
                            m = Literal(IntegerLyraType(), "1")
                            c = [do(x, y) for x, y in zip(c1, c2)]
                            if len(c1) != len(
                                    c2
                            ):  # lengths of list of constraints are different
                                c.append(())  # add a star constraint
                        else:
                            assert m1 == m2
                            m: Expression = m1
                            c = [do(x, y) for x, y in zip(c1, c2)]
                            c.extend(c1[len(c2):])
                            c.extend(c2[len(c1):])
                        return AssumptionState.InputStack.InputLattice(m, c)

                multiplier1 = self.multiplier
                multiplier2 = other.multiplier
                assert isinstance(multiplier1,
                                  Literal) and multiplier1.val == "1"
                assert isinstance(multiplier2,
                                  Literal) and multiplier2.val == "1"
                constraints = [
                    do(x, y)
                    for x, y in zip(self.constraints, other.constraints)
                ]
                one = Literal(IntegerLyraType(), "1")
                return self._replace(
                    AssumptionState.InputStack.InputLattice(one, constraints))
Exemplo n.º 15
0
    def __init__(self, variables: Set[VariableIdentifier], precursory: State = None):
        """Map each program variable to the interval representing its value.

        :param variables: set of program variables
        """
        lattices = defaultdict(lambda: IntervalLattice)
        super().__init__(variables, lattices, precursory=precursory)
        for v in self.variables:
            if isinstance(v.typ, SequenceLyraType):
                self.store[LengthIdentifier(v)] = lattices[IntegerLyraType()](lower=0)
Exemplo n.º 16
0
    def __init__(self, variables: Set[VariableIdentifier], precursory: InputMixin = None):
        """Map each program variable to the interval representing its value.

        :param variables: set of program variables
        """
        lattices = defaultdict(lambda: RangeLattice)
        super(IntervalStateWithSummarization, self).__init__(variables, lattices)
        InputMixin.__init__(self, precursory)
        for v in self.variables:
            if isinstance(v.typ, SequenceLyraType):
                self.lengths[LengthIdentifier(v)] = lattices[IntegerLyraType()](lower=0)
Exemplo n.º 17
0
 def visit_Num(self, node, types=None, typ=None):
     """Visitor function for a number (integer, float, or complex).
     The n attribute stores the value, already converted to the relevant type."""
     pp = ProgramPoint(node.lineno, node.col_offset)
     if isinstance(node.n, int):
         expr = Literal(IntegerLyraType(), str(node.n))
         return LiteralEvaluation(pp, expr)
     elif isinstance(node.n, float):
         expr = Literal(FloatLyraType(), str(node.n))
         return LiteralEvaluation(pp, expr)
     raise NotImplementedError(f"Num of type {node.n.__class__.__name__} is unsupported!")
Exemplo n.º 18
0
    def __init__(self, key_domain: Type[KeyWrapper],
                 precursory: FularaState,
                 scalar_vars: Set[VariableIdentifier] = None,
                 map_vars: Set[VariableIdentifier] = None,
                 k_pre_k_conv: Callable[[KeyWrapper], KeyWrapper]
                 = lambda x: x):
        """Map each program variable/dictionary segment to its liveness status.
        :param key_domain: domain for abstraction of dictionary keys,
            ranges over the scalar variables and the special key variable v_k,
            should support backward assignments with _substitute
        :param precursory: Forward analysis (Fulara analysis) result above the current statement
        :param scalar_vars: list of scalar variables, whose liveness should be abstracted
        :param map_vars: list of map variables, whose usage should be abstracted
        :param k_pre_k_conv: Conversion function to convert from key domain elements of the
                             precursory analysis to key domain elements of this analysis
                             (if the domains differ)
        """

        super().__init__(precursory)

        self._s_vars = scalar_vars or set()
        self._m_vars = map_vars or set()

        self._k_domain = key_domain

        self._scalar_liveness = StrongLivenessState(scalar_vars)

        arguments = {}
        for dv in map_vars:
            typ = dv.typ
            if isinstance(typ, DictLyraType):
                k_var = VariableIdentifier(typ.key_typ, k_name)
            elif isinstance(typ, ListLyraType):
                k_var = VariableIdentifier(IntegerLyraType(), k_name)
            else:
                raise TypeError("Map variables should be of type DictLyraType or ListLyraType")

            if typ not in arguments:
                arguments[typ] = {'key_domain': key_domain, 'value_domain': LivenessLattice,
                                  'key_d_args': {'scalar_variables': scalar_vars, 'k_var': k_var}}

        lattices = defaultdict(lambda: FularaLattice)
        self._dict_liveness = Store(map_vars, lattices, arguments)
        # start with 'dead'
        for var in map_vars:
            self._dict_liveness.store[var].empty()

        # self._length_usage

        self._k_pre_k_conv = k_pre_k_conv
Exemplo n.º 19
0
    def __init__(self,
                 key_domain: Type[Union[KeyWrapper, State]],
                 scalar_vars: Set[VariableIdentifier] = None,
                 map_vars: Set[VariableIdentifier] = None):
        """Map each program variable/dictionary segment to its usage status.

        :param key_domain: domain for abstraction of dictionary keys,
            ranges over the scalar variables and the special key variable v_k
        :param scalar_vars: list of scalar variables, whose usage should be abstracted
        :param map_vars: list of map variables, whose usage should be abstracted
        """
        super().__init__()

        self._s_vars = scalar_vars or set()
        self._m_vars = map_vars or set()

        self._k_domain = key_domain

        self._scalar_usage = SimpleUsageStore(scalar_vars)

        arguments = {}
        for dv in map_vars:
            typ = dv.typ
            if isinstance(typ, DictLyraType):
                k_var = VariableIdentifier(typ.key_typ, k_name)
            elif isinstance(typ, ListLyraType):
                k_var = VariableIdentifier(IntegerLyraType(), k_name)
            else:
                raise TypeError(
                    "Map variables should be of type DictLyraType or ListLyraType"
                )

            if typ not in arguments:
                arguments[typ] = {
                    'key_domain': key_domain,
                    'value_domain': UsageLattice,
                    'key_d_args': {
                        'scalar_variables': scalar_vars,
                        'k_var': k_var
                    }
                }

        lattices = defaultdict(lambda: FularaLattice)
        self._dict_usage = Store(map_vars, lattices, arguments)
        # start with 'not used'
        for var in map_vars:
            self._dict_usage.store[var].empty()

        self._loop_flag = False
Exemplo n.º 20
0
 def visit_BinaryArithmeticOperation(self,
                                     expr,
                                     evaluation=None,
                                     value=None,
                                     state=None):
     updated = super().visit_BinaryArithmeticOperation(
         expr, evaluation, value, state)
     if expr.operator == BinaryArithmeticOperation.Operator.Div:
         left = expr.right
         operator = BinaryComparisonOperation.Operator.NotEq
         right = Literal(IntegerLyraType(), "0")
         condition = BinaryComparisonOperation(BooleanLyraType(), left,
                                               operator, right)
         return updated.assume({condition})
     return updated
Exemplo n.º 21
0
 def visit_Literal(self, expr: Literal, state=None):
     if isinstance(expr.typ, StringLyraType):
         return state.lattices[IntegerLyraType()](len(expr.val), len(expr.val))
     raise ValueError(f"Unexpected expression during sequence length computation.")
Exemplo n.º 22
0
 def visit_BinaryComparisonOperation(self,
                                     expr: 'BinaryComparisonOperation',
                                     invert=False):
     left = expr.left
     operator = expr.operator.reverse_operator(
     ) if invert else expr.operator
     right = expr.right
     if operator == BinaryComparisonOperation.Operator.Eq:
         # left = right -> left - right <= 0 && right - left <= 0
         zero = Literal(IntegerLyraType(), "0")
         minus = BinaryArithmeticOperation.Operator.Sub
         operator = BinaryComparisonOperation.Operator.LtE
         expr1 = BinaryArithmeticOperation(left.typ, left, minus, right)
         expr1 = BinaryComparisonOperation(expr.typ, expr1, operator, zero)
         expr2 = BinaryArithmeticOperation(right.typ, right, minus, left)
         expr2 = BinaryComparisonOperation(expr.typ, expr2, operator, zero)
         conjunction = BinaryBooleanOperation.Operator.And
         return BinaryBooleanOperation(expr.typ, expr1, conjunction, expr2)
     elif operator == BinaryComparisonOperation.Operator.NotEq:
         # left != right -> left - (right - 1) <= 0 || right - (left - 1) <= 0
         zero = Literal(IntegerLyraType(), "0")
         one = Literal(IntegerLyraType(), "1")
         minus = BinaryArithmeticOperation.Operator.Sub
         operator = BinaryComparisonOperation.Operator.LtE
         expr1 = BinaryArithmeticOperation(right.typ, right, minus, one)
         expr1 = BinaryArithmeticOperation(left.typ, left, minus, expr1)
         expr1 = BinaryComparisonOperation(expr.typ, expr1, operator, zero)
         expr2 = BinaryArithmeticOperation(left.typ, left, minus, one)
         expr2 = BinaryArithmeticOperation(right.typ, right, minus, expr2)
         expr2 = BinaryComparisonOperation(expr.typ, expr2, operator, zero)
         disjunction = BinaryBooleanOperation.Operator.Or
         return BinaryBooleanOperation(expr.typ, expr1, disjunction, expr2)
     elif operator == BinaryComparisonOperation.Operator.Lt:
         # left < right -> left - (right - 1) <= 0
         zero = Literal(IntegerLyraType(), "0")
         one = Literal(IntegerLyraType(), "1")
         minus = BinaryArithmeticOperation.Operator.Sub
         right = BinaryArithmeticOperation(right.typ, right, minus, one)
         left = BinaryArithmeticOperation(left.typ, left, minus, right)
         operator = BinaryComparisonOperation.Operator.LtE
         return BinaryComparisonOperation(expr.typ, left, operator, zero)
     elif operator == BinaryComparisonOperation.Operator.LtE:
         # left <= right -> left - right <= 0
         zero = Literal(IntegerLyraType(), "0")
         minus = BinaryArithmeticOperation.Operator.Sub
         left = BinaryArithmeticOperation(left.typ, left, minus, right)
         operator = BinaryComparisonOperation.Operator.LtE
         return BinaryComparisonOperation(expr.typ, left, operator, zero)
     elif operator == BinaryComparisonOperation.Operator.Gt:
         # left > right -> right - (left - 1) <= 0
         zero = Literal(IntegerLyraType(), "0")
         one = Literal(IntegerLyraType(), "1")
         minus = BinaryArithmeticOperation.Operator.Sub
         left = BinaryArithmeticOperation(left.typ, left, minus, one)
         right = BinaryArithmeticOperation(right.typ, right, minus, left)
         operator = BinaryComparisonOperation.Operator.LtE
         return BinaryComparisonOperation(expr.typ, right, operator, zero)
     elif operator == BinaryComparisonOperation.Operator.GtE:
         # left >= right -> right - left <= 0
         zero = Literal(IntegerLyraType(), "0")
         minus = BinaryArithmeticOperation.Operator.Sub
         right = BinaryArithmeticOperation(right.typ, right, minus, left)
         operator = BinaryComparisonOperation.Operator.LtE
         return BinaryComparisonOperation(expr.typ, right, operator, zero)
     elif operator == BinaryComparisonOperation.Operator.In:
         return BinaryComparisonOperation(expr.typ, left, operator, right)
     elif operator == BinaryComparisonOperation.Operator.NotIn:
         return BinaryComparisonOperation(expr.typ, left, operator, right)
     raise ValueError(f"Boolean comparison operator {expr} is unsupported!")
Exemplo n.º 23
0
 def visit_SetDisplay(self, expr: SetDisplay, state=None):
     return state.lattices[IntegerLyraType()](len(expr.items), len(expr.items))
Exemplo n.º 24
0
 def visit_Subscription(self, expr: Subscription, state=None):
     return state.lattices[IntegerLyraType()](lower=1, upper=1)
Exemplo n.º 25
0
 def visit_Input(self, expr: Input, state=None):
     return state.lattices[IntegerLyraType()](lower=0)
Exemplo n.º 26
0
 def visit_Values(self, expr: Values, state=None):
     return state.lattices[IntegerLyraType()](lower=0)
Exemplo n.º 27
0
 def top(self):
     """The top lattice element is ``1 * [★]``."""
     one = Literal(IntegerLyraType(), "1")
     return self._replace(
         AssumptionState.InputStack.InputLattice(one, [()]))