Example #1
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)
Example #2
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
Example #3
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!")
Example #4
0
 def __init__(self,
              multiplier: Expression = Literal(
                  IntegerLyraType(), "1"),
              constraints: List[InputConstraint] = list()):
     super().__init__()
     self._multiplier = multiplier
     self._constraints = constraints
Example #5
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)
Example #6
0
    def _cast_call_semantics(self, stmt: Call, state: State,
                             typ: LyraType) -> State:
        """Semantics of a call to 'int' or 'bool'.

        :param stmt: call to 'int' or 'bool' to be executed
        :param state: state before executing the call statement
        :return: state modified by the call statement
        """
        if len(stmt.arguments) != 1:
            error = f"Semantics for multiple arguments of {stmt.name} is not yet implemented!"
            raise NotImplementedError(error)
        argument = self.semantics(stmt.arguments[0], state).result
        result = set()
        for expression in argument:
            if isinstance(expression, Input):
                result.add(Input(typ))
            elif isinstance(expression, Literal):
                result.add(Literal(typ, expression.val))
            elif isinstance(expression, VariableIdentifier):
                result.add(VariableIdentifier(typ, expression.name))
            elif isinstance(expression, Subscription):
                pass  # TODO
            else:
                error = f"Argument of type {expression.typ} of {stmt.name} is not yet supported!"
                raise NotImplementedError(error)
        state.result = result
        return state
Example #7
0
 def split_call_semantics(self, stmt: Call, state: State) -> State:
     if len(stmt.arguments) != 1:
         error = f"Semantics for multiple arguments of {stmt.name} is not yet implemented!"
         raise NotImplementedError(error)
     argument = self.semantics(stmt.arguments[0], state).result
     result = set()
     for arg in argument:
         assert isinstance(arg, Expression)
         if not isinstance(arg.typ, StringLyraType):
             error = f"Call to {stmt.name} of argument with unexpected type!"
             raise ValueError(error)
         typ = ListLyraType(StringLyraType())
         if isinstance(arg, Literal):  # "a b c".split() -> ["a", "b", "c"]
             items = [
                 Literal(StringLyraType(), val) for val in arg.val.split()
             ]
             result.add(ListDisplay(typ, items))
             continue
         elif isinstance(arg, VariableIdentifier):  # x.split()
             result.add(VariableIdentifier(typ, arg.name))
             continue
         elif isinstance(arg, Input):  # input().split()
             result.add(Input(typ))
             continue
         error = f"Call to {stmt.name} of unexpected argument!"
         raise ValueError(error)
     state.result = result
     return state
Example #8
0
 def visit_NameConstant(self, node, types=None, typ=None):
     """Visitor function for True, False or None.
     The value attribute stores the constant."""
     if isinstance(node.value, bool):
         pp = ProgramPoint(node.lineno, node.col_offset)
         expr = Literal(BooleanLyraType(), str(node.value))
         return LiteralEvaluation(pp, expr)
     raise NotImplementedError(f"Constant {node.value.__class__.__name__} is unsupported!")
Example #9
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
Example #10
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))
Example #11
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
Example #12
0
 def do(lattice, typ, key, current: Lattice) -> Lattice:
     updated: Lattice = current
     if isinstance(typ, (BooleanLyraType, IntegerLyraType,
                         FloatLyraType, StringLyraType)):
         if hasattr(lattice, 'from_literal'):
             literal = Literal(typ, key)
             updated = updated.join(lattice.from_literal(literal))
         else:
             updated = updated.join(lattice().top())
     else:
         assert isinstance(typ, TupleLyraType)
         val = literal_eval(key)
         for i, subtyp in enumerate(typ.typs):
             updated = do(lattice, subtyp, val[i], updated)
     return updated
Example #13
0
    def from_literal(cls,
                     lattice: Type[Lattice],
                     literal: Literal,
                     bound: int = 3):
        """Indexed lattice creation from a literal expression.

        :param lattice: the (sub)lattice whose elements are to be indexed
        :param literal: the literal
        :param bound: bound on the size of the index
        """
        if isinstance(literal.typ, StringLyraType):
            index = dict()
            for idx, item in enumerate(literal.val):
                if hasattr(lattice, 'from_literal'):
                    index[str(idx)] = lattice.from_literal(
                        Literal(StringLyraType(), item))
                else:
                    index[str(idx)] = lattice().top()
            return cls(lattice, index, bound)
        return cls(lattice, None, 3)
Example #14
0
    def _cast_call_semantics(self, stmt: Call, state, interpreter,
                             typ: LyraType) -> State:
        """Semantics of a call to 'int', 'bool', or 'float'.

        :param stmt: call to 'int', 'bool', 'float', or 'str' to be executed
        :param state: state before executing the call statement
        :return: state modified by the call statement
        """
        if len(stmt.arguments) != 1:
            error = f"Semantics for multiple arguments of {stmt.name} is not yet implemented!"
            raise NotImplementedError(error)
        argument = self.semantics(stmt.arguments[0], state, interpreter).result
        result = set()
        for expression in argument:
            if isinstance(expression, Input):
                result.add(Input(typ))
            elif isinstance(expression, Literal):
                result.add(Literal(typ, expression.val))
            else:
                result.add(CastOperation(typ, expression))
        state.result = result
        return state
Example #15
0
 def visit_Literal(self, expr: Literal):
     return Literal(expr.typ, expr.val)
Example #16
0
 def top(self):
     """The top lattice element is ``1 * [★]``."""
     one = Literal(IntegerLyraType(), "1")
     return self._replace(
         AssumptionState.InputStack.InputLattice(one, [()]))
Example #17
0
 def visit_Str(self, node, types=None, typ=None):
     """Visitor function for a string. The s attribute stores the value."""
     pp = ProgramPoint(node.lineno, node.col_offset)
     expr = Literal(StringLyraType(), node.s)
     return LiteralEvaluation(pp, expr)