Ejemplo n.º 1
0
 def assign_to_Name(self, node: ast.Name, value: Expr, res: List[Expr],
                    ctx: Context):
     pos = self.to_position(node, ctx)
     var = ctx.locals.get(node.id)
     w_value = value
     if var:
         if isinstance(var, TranslatedPureIndexedVar):
             var.new_idx()
         if (types.is_numeric(node.type) and not var.is_local
                 and self.expression_translator.arithmetic_translator.
                 is_unwrapped(value)):
             w_value = helpers.w_wrap(self.viper_ast, value)
         elif (types.is_numeric(node.type) and var.is_local
               and self.expression_translator.arithmetic_translator.
               is_wrapped(value)):
             var.is_local = False
         elif (types.is_numeric(node.type) and self._always_wrap
               and var.is_local and self.expression_translator.
               arithmetic_translator.is_unwrapped(value)):
             var.is_local = False
             w_value = helpers.w_wrap(self.viper_ast, value)
         elif (not types.is_numeric(node.type)
               and self.expression_translator.arithmetic_translator.
               is_wrapped(value)):
             w_value = helpers.w_unwrap(self.viper_ast, value)
     lhs = self.expression_translator.translate(node, res, ctx)
     assign = self.viper_ast.EqCmp(lhs, w_value, pos)
     expr = self.viper_ast.Implies(ctx.pure_conds, assign,
                                   pos) if ctx.pure_conds else assign
     res.append(expr)
Ejemplo n.º 2
0
 def _wrapped_decimal_div(self, lhs, rhs, pos=None, info=None) -> Expr:
     scaling_factor = self.viper_ast.IntLit(
         types.VYPER_DECIMAL.scaling_factor, pos)
     uw_lhs = helpers.w_unwrap(self.viper_ast, lhs, pos)
     uw_mult = self.viper_ast.Mul(uw_lhs, scaling_factor, pos)
     mult = helpers.w_wrap(self.viper_ast, uw_mult, pos)
     return helpers.w_div(self.viper_ast, mult, rhs, pos, info)
Ejemplo n.º 3
0
    def default_value(self,
                      node: Optional[ast.Node],
                      type: VyperType,
                      res: List[Stmt],
                      ctx: Context,
                      is_local=True) -> Expr:
        pos = self.no_position() if node is None else self.to_position(
            node, ctx)
        if type is types.VYPER_BOOL:
            return self.viper_ast.FalseLit(pos)
        elif isinstance(type, PrimitiveType):
            if is_local:
                return self.viper_ast.IntLit(0, pos)
            else:
                return helpers.w_wrap(self.viper_ast,
                                      self.viper_ast.IntLit(0, pos), pos)
        elif isinstance(type, MapType):
            key_type = self.translate(type.key_type, ctx)
            value_type = self.translate(type.value_type, ctx)

            value_default = self.default_value(node, type.value_type, res, ctx)
            return helpers.map_init(self.viper_ast, value_default, key_type,
                                    value_type, pos)
        elif isinstance(type, ArrayType):
            sizes = [type.size]
            curr_type = type
            while isinstance(curr_type.element_type, ArrayType):
                # noinspection PyUnresolvedReferences
                sizes.append(curr_type.element_type.size)
                curr_type = curr_type.element_type
            element_type = self.translate(curr_type.element_type, ctx)
            if type.is_strict:
                result = self.default_value(node, curr_type.element_type, res,
                                            ctx)
                result_type = element_type
                for size in sizes:
                    result = helpers.array_init(self.viper_ast, result, size,
                                                result_type, pos)
                    result_type = helpers.array_type(self.viper_ast,
                                                     result_type)
                return result
            else:
                return helpers.empty_array(self.viper_ast, element_type, pos)
        elif isinstance(type, StructType):
            init_args = {}
            for name, member_type in type.member_types.items():
                idx = type.member_indices[name]
                val = self.default_value(node, member_type, res, ctx)
                init_args[idx] = val
            args = [init_args[i] for i in range(len(init_args))]
            return helpers.struct_init(self.viper_ast, args, type, pos)
        elif isinstance(type, (ContractType, InterfaceType)):
            return self.default_value(node, types.VYPER_ADDRESS, res, ctx)
        elif isinstance(type, TupleType):
            return helpers.havoc_var(self.viper_ast,
                                     helpers.struct_type(self.viper_ast), ctx)
        else:
            assert False
Ejemplo n.º 4
0
 def wrap(a: Expr) -> Expr:
     if hasattr(a, 'isSubtype') and a.isSubtype(
             _self.viper_ast.Int):
         return helpers.w_wrap(_self.viper_ast, a, pos, info)
     return a
Ejemplo n.º 5
0
    def translate_For(self, node: ast.For, res: List[Expr], ctx: Context):
        pos = self.to_position(node, ctx)

        pre_conds = ctx.pure_conds

        self._add_local_var(node.target, ctx)
        loop_var_name = node.target.id
        loop_var = ctx.locals[loop_var_name]
        assert isinstance(loop_var, TranslatedPureIndexedVar)
        array = self.expression_translator.translate_top_level_expression(
            node.iter, res, ctx)
        loop_var.is_local = False
        array_var = TranslatedPureIndexedVar('array',
                                             'array',
                                             node.iter.type,
                                             self.viper_ast,
                                             pos,
                                             is_local=False)
        res.append(self.viper_ast.EqCmp(array_var.local_var(ctx), array, pos))
        array_local_var = array_var.local_var(ctx)

        times = node.iter.type.size
        lpos = self.to_position(node.target, ctx)
        rpos = self.to_position(node.iter, ctx)

        if times > 0:
            has_numeric_array = types.is_numeric(node.target.type)
            loop_invariants = ctx.function.loop_invariants.get(node)
            if loop_invariants:
                # loop-array expression
                ctx.loop_arrays[loop_var_name] = array_local_var
                # New variable loop-idx
                loop_idx_var = TranslatedPureIndexedVar(
                    'idx', 'idx', VYPER_UINT256, self.viper_ast, pos)
                ctx.loop_indices[loop_var_name] = loop_idx_var
                loop_idx_local_var = loop_idx_var.local_var(ctx)
                # Havoc used variables
                loop_used_var = {}
                for var_name in ctx.function.analysis.loop_used_names.get(
                        loop_var_name, []):
                    if var_name == loop_var_name:
                        continue
                    var = ctx.locals.get(var_name)
                    if var and isinstance(var, TranslatedPureIndexedVar):
                        # Create new variable
                        mangled_name = ctx.new_local_var_name(var.name)
                        new_var = TranslatedPureIndexedVar(
                            var.name, mangled_name, var.type, var.viper_ast,
                            var.pos, var.info, var.is_local)
                        copy_expr = self.viper_ast.EqCmp(
                            new_var.local_var(ctx), var.local_var(ctx), rpos)
                        res.append(copy_expr)
                        loop_used_var[var.name] = new_var
                        # Havoc old var
                        var.new_idx()
                        var.is_local = False
                # Assume loop 0 <= index < |array|
                loop_idx_ge_zero = self.viper_ast.GeCmp(
                    loop_idx_local_var, self.viper_ast.IntLit(0), rpos)
                times_lit = self.viper_ast.IntLit(times)
                loop_idx_lt_array_size = self.viper_ast.LtCmp(
                    loop_idx_local_var, times_lit, rpos)
                loop_idx_assumption = self.viper_ast.And(
                    loop_idx_ge_zero, loop_idx_lt_array_size, rpos)
                res.append(loop_idx_assumption)
                # Set loop variable to array[index]
                array_at = self.viper_ast.SeqIndex(array_local_var,
                                                   loop_idx_local_var, rpos)
                if has_numeric_array:
                    array_at = helpers.w_wrap(self.viper_ast, array_at)
                set_loop_var = self.viper_ast.EqCmp(loop_var.local_var(ctx),
                                                    array_at, lpos)
                res.append(set_loop_var)
                with ctx.old_local_variables_scope(loop_used_var):
                    with ctx.state_scope(ctx.current_state, ctx.current_state):
                        for loop_invariant in loop_invariants:
                            cond_pos = self.to_position(loop_invariant, ctx)
                            inv = self.specification_translator.translate_pre_or_postcondition(
                                loop_invariant, res, ctx)
                            inv_var = TranslatedPureIndexedVar(
                                'inv', 'inv', VYPER_BOOL, self.viper_ast,
                                cond_pos)
                            inv_local_var = inv_var.local_var(ctx)
                            assign = self.viper_ast.EqCmp(
                                inv_local_var, inv, cond_pos)
                            expr = self.viper_ast.Implies(
                                pre_conds, assign,
                                cond_pos) if pre_conds else assign
                            res.append(expr)
                            ctx.pure_conds = self.viper_ast.And(ctx.pure_conds, inv_local_var, pos)\
                                if ctx.pure_conds else inv_local_var
                # Store state before loop body
                pre_locals = self._local_variable_snapshot(ctx)
                pre_loop_iteration_conds = ctx.pure_conds
                # Loop Body
                with ctx.break_scope():
                    with ctx.continue_scope():
                        with self.assignment_translator.assume_everything_has_wrapped_information(
                        ):
                            with ctx.new_local_scope():
                                self.translate_stmts(node.body, res, ctx)
                        ctx.pure_conds = pre_loop_iteration_conds
                        # After loop body increase idx
                        loop_idx_inc = self.viper_ast.Add(
                            loop_idx_local_var, self.viper_ast.IntLit(1), pos)
                        loop_idx_var.new_idx()
                        loop_idx_local_var = loop_idx_var.local_var(ctx)
                        res.append(
                            self.viper_ast.EqCmp(loop_idx_local_var,
                                                 loop_idx_inc, pos))
                        # Break if we reached the end of the array we iterate over
                        loop_idx_eq_times = self.viper_ast.EqCmp(
                            loop_idx_local_var, times_lit, pos)
                        cond_var = TranslatedPureIndexedVar(
                            'cond', 'cond', VYPER_BOOL, self.viper_ast, pos)
                        cond_local_var = cond_var.local_var(ctx)
                        res.append(
                            self.viper_ast.EqCmp(cond_local_var,
                                                 loop_idx_eq_times, pos))
                        break_cond = self.viper_ast.And(ctx.pure_conds, cond_local_var, pos)\
                            if ctx.pure_conds else cond_local_var
                        ctx.pure_breaks.append(
                            (break_cond, self._local_variable_snapshot(ctx)))

                    # Assume that only one of the breaks happened
                    only_one_break_cond = self._xor_conds(
                        [x for x, _ in ctx.pure_breaks])
                    assert only_one_break_cond is not None
                    if pre_conds is None:
                        res.append(only_one_break_cond)
                    else:
                        res.append(
                            self.viper_ast.Implies(pre_conds,
                                                   only_one_break_cond))
                    # Merge snapshots
                    prev_snapshot = pre_locals
                    for cond, snapshot in reversed(ctx.pure_breaks):
                        prev_snapshot = self._merge_snapshots(
                            cond, snapshot, prev_snapshot, res, ctx)
            else:
                # Unroll loop if we have no loop invariants
                pre_loop_locals = self._local_variable_snapshot(ctx)
                with ctx.break_scope():
                    for i in range(times):
                        pre_loop_iteration_conds = ctx.pure_conds
                        with ctx.continue_scope():
                            idx = self.viper_ast.IntLit(i, lpos)
                            array_at = self.viper_ast.SeqIndex(
                                array_local_var, idx, rpos)
                            if has_numeric_array:
                                array_at = helpers.w_wrap(
                                    self.viper_ast, array_at)
                            loop_var.new_idx()
                            var_set = self.viper_ast.EqCmp(
                                loop_var.local_var(ctx), array_at, lpos)
                            res.append(var_set)

                            pre_it_locals = self._local_variable_snapshot(ctx)
                            with self.assignment_translator.assume_everything_has_wrapped_information(
                            ):
                                with ctx.new_local_scope():
                                    self.translate_stmts(node.body, res, ctx)

                            post_it_locals = self._local_variable_snapshot(ctx)
                            ctx.pure_continues.append(
                                (ctx.pure_conds, post_it_locals))

                            prev_snapshot = pre_it_locals
                            for cond, snapshot in reversed(ctx.pure_continues):
                                prev_snapshot = self._merge_snapshots(
                                    cond, snapshot, prev_snapshot, res, ctx)

                        ctx.pure_conds = pre_loop_iteration_conds

                    post_loop_locals = self._local_variable_snapshot(ctx)
                    ctx.pure_breaks.append((ctx.pure_conds, post_loop_locals))

                    prev_snapshot = pre_loop_locals
                    for cond, snapshot in reversed(ctx.pure_breaks):
                        prev_snapshot = self._merge_snapshots(
                            cond, snapshot, prev_snapshot, res, ctx)
        ctx.pure_conds = pre_conds
Ejemplo n.º 6
0
    def arithmetic_op(self,
                      lhs,
                      op: ast.ArithmeticOperator,
                      rhs,
                      otype: PrimitiveType,
                      res: List[Stmt],
                      ctx: Context,
                      pos=None) -> Expr:
        ast_op = ast.ArithmeticOperator
        left_is_wrapped = self.is_wrapped(lhs)
        right_is_wrapped = self.is_wrapped(rhs)
        if ctx.inside_interpreted:
            if left_is_wrapped:
                left_is_wrapped = False
                lhs = helpers.w_unwrap(self.viper_ast, lhs, pos)
            if right_is_wrapped:
                right_is_wrapped = False
                rhs = helpers.w_unwrap(self.viper_ast, rhs, pos)
        elif ctx.inside_lemma:
            if not left_is_wrapped:
                left_is_wrapped = True
                lhs = helpers.w_wrap(self.viper_ast, lhs, pos)
            if not right_is_wrapped:
                right_is_wrapped = True
                rhs = helpers.w_wrap(self.viper_ast, rhs, pos)
        with switch(op, otype) as case:
            from twovyper.utils import _

            if (case(ast_op.DIV, _)
                    or case(ast_op.MOD, _)) and not self.no_reverts:
                expr = rhs
                if right_is_wrapped:
                    expr = helpers.w_unwrap(self.viper_ast, rhs, pos)
                cond = self.viper_ast.EqCmp(expr,
                                            self.viper_ast.IntLit(0, pos), pos)
                self.fail_if(cond, [], res, ctx, pos)

            if left_is_wrapped and right_is_wrapped:
                # Both are wrapped
                if case(ast_op.MUL, types.VYPER_DECIMAL):
                    expr = self._wrapped_decimal_mul(lhs, rhs, pos)
                elif case(ast_op.DIV, types.VYPER_DECIMAL):
                    expr = self._wrapped_decimal_div(lhs, rhs, pos)
                else:
                    expr = self._wrapped_arithmetic_ops[op](lhs, rhs, pos)
            else:
                if case(ast_op.MUL, types.VYPER_DECIMAL):
                    expr = self._decimal_mul(lhs, rhs, pos)
                elif case(ast_op.DIV, types.VYPER_DECIMAL):
                    expr = self._decimal_div(lhs, rhs, pos)
                else:
                    expr = self._arithmetic_ops[op](lhs, rhs, pos)

        if types.is_bounded(otype):
            assert isinstance(otype, BoundedType)
            if is_compatible_version('<=0.1.0-beta.17') and op == ast_op.POW:
                # In certain versions of Vyper there was no overflow check for POW.
                self.check_underflow(expr, otype, res, ctx, pos)
            else:
                self.check_under_overflow(expr, otype, res, ctx, pos)

        return expr