Esempio n. 1
0
    def translate_let(self,
                      node: ast.Call,
                      ctx: Context,
                      impure: bool = False) -> StmtsAndExpr:
        type = self.get_target(node.args[1], ctx)
        if not isinstance(type, PythonType) or not isinstance(
                node.args[2], ast.Lambda):
            raise InvalidProgramException(node, 'invalid.let')
        lambda_ = node.args[2]
        lambda_prefix = construct_lambda_prefix(
            lambda_.lineno, getattr(lambda_, 'col_offset', None))
        lambda_prefix += '$'
        arg = lambda_.args.args[0]
        var = ctx.actual_function.get_variable(lambda_prefix + arg.arg)

        exp_stmt, exp_val = self.translate_expr(node.args[0], ctx)

        ctx.set_alias(arg.arg, var, None)

        body_stmt, body_val = self.translate_expr(lambda_.body,
                                                  ctx,
                                                  impure=impure)

        ctx.remove_alias(arg.arg)
        pos = self.to_position(node, ctx)
        info = self.no_info(ctx)
        let = self.viper.Let(var.decl, exp_val, body_val, pos, info)
        return exp_stmt + body_stmt, let
Esempio n. 2
0
    def visit_Return(self, node: ast.Return) -> None:
        """Parse IO operation body.

        IO operation body must be a single expression that is returned.
        """
        body = node.value
        lambda_ = None

        if (isinstance(body, ast.Call) and isinstance(body.func, ast.Call)
                and isinstance(body.func.func, ast.Name)
                and body.func.func.id.startswith('IOExists')):
            lambda_ = cast(ast.Lambda, body.args[0])
            args = lambda_.args.args
            io_existential_creators = [
                self._node_factory.create_python_var_creator(
                    arg.arg, arg, self._typeof(arg, lambda_)) for arg in args
            ]
            body = lambda_.body
        else:
            io_existential_creators = []
        if not self._current_io_operation.set_body(body):
            self._raise_invalid_operation('duplicate_body', node)
        assert self._current_io_operation.set_io_existentials(
            io_existential_creators)
        if lambda_ is not None:
            prefix = construct_lambda_prefix(lambda_.lineno,
                                             lambda_.col_offset)
            self._current_lambdas.append(prefix)
            self.visit(node.value.args[0].body)
            self._current_lambdas.pop()
        else:
            self.visit(node.value)
Esempio n. 3
0
 def visit_func_expr(self, node: mypy.nodes.FuncExpr):
     oldprefix = self.prefix
     prefix_string = construct_lambda_prefix(node.line, col(node))
     self.prefix = self.prefix + [prefix_string]
     for arg in node.arguments:
         self.set_type(self.prefix + [arg.variable.name()],
                       arg.variable.type, arg.line, col(arg))
     node.body.accept(self)
     self.prefix = oldprefix
Esempio n. 4
0
 def visit_lambda_expr(self, node: mypy.nodes.LambdaExpr):
     oldprefix = self.prefix
     prefix_string = construct_lambda_prefix(node.line, col(node))
     self.prefix = self.prefix + [prefix_string]
     for arg in node.arguments:
         self.set_type(self.prefix + [arg.variable.name], arg.variable.type,
                       arg.line, col(arg))
     self.visit(node.body)
     self.prefix = oldprefix
Esempio n. 5
0
 def _typeof(self,
             node: ast.AST,
             lambda_: ast.Lambda = None) -> nodes.PythonType:
     """Get the type of the given AST node."""
     assert isinstance(node, ast.arg)
     if (self._current_io_operation.name == EVAL_IO_SIGNATURE[0]
             and node.arg == EVAL_IO_SIGNATURE[2]):
         return self._parent.module.global_module.classes[OBJECT_TYPE]
     scopes = [self._current_io_operation.name]
     if lambda_:
         prefix = construct_lambda_prefix(lambda_.lineno,
                                          lambda_.col_offset)
         scopes.append(prefix)
     typ, _ = self._parent.module.get_type(scopes, node.arg)
     # to avoid problems with boxed versions not being reference-equal,
     # always use unboxed versions
     result = self._parent.convert_type(typ, node).try_unbox()
     return result
Esempio n. 6
0
    def translate_forall(self,
                         node: ast.Call,
                         ctx: Context,
                         impure=False) -> StmtsAndExpr:
        domain_node = node.args[0]

        lambda_ = node.args[1]
        variables = []
        lambda_prefix = construct_lambda_prefix(
            lambda_.lineno, getattr(lambda_, 'col_offset', None))
        lambda_prefix += '$'
        arg = lambda_.args.args[0]
        var = ctx.actual_function.get_variable(lambda_prefix + arg.arg)
        variables.append(var.decl)

        ctx.set_alias(arg.arg, var, None)
        if isinstance(lambda_.body, ast.Tuple):
            if not len(lambda_.body.elts) == 2:
                raise InvalidProgramException(node, 'invalid.forall')
            body_stmt, rhs = self.translate_expr(lambda_.body.elts[0], ctx,
                                                 self.viper.Bool, impure)

            triggers = self._translate_triggers(lambda_.body, node, ctx)
        else:
            body_type = self.get_type(lambda_.body, ctx)
            if not body_type or body_type.name != BOOL_TYPE:
                raise InvalidProgramException(node, 'invalid.forall')
            body_stmt, rhs = self.translate_expr(lambda_.body, ctx,
                                                 self.viper.Bool, impure)
            triggers = []

        ctx.remove_alias(arg.arg)
        if body_stmt:
            raise InvalidProgramException(node, 'purity.violated')

        dom_stmt, lhs, always_use = self._create_quantifier_contains_expr(
            var.ref(), domain_node, ctx)
        if dom_stmt:
            raise InvalidProgramException(domain_node, 'purity.violated')
        lhs = self.unwrap(lhs)

        implication = self.viper.Implies(lhs, rhs, self.to_position(node, ctx),
                                         self.no_info(ctx))
        if always_use or not triggers:
            # Add lhs of the implication, which the user cannot write directly
            # in this exact form.
            # If we always do this, we apparently deactivate the automatically
            # generated triggers and things are actually worse.
            # Change: We always do this now.
            try:
                # Depending on the collection expression, this doesn't always
                # work (malformed trigger); in that case, we just don't do it.
                lhs_trigger = self.viper.Trigger([lhs], self.no_position(ctx),
                                                 self.no_info(ctx))
                triggers = [lhs_trigger] + triggers
            except Exception:
                pass
        var_type_check = self.type_check(var.ref(), var.type,
                                         self.no_position(ctx), ctx, False)
        implication = self.viper.Implies(var_type_check, implication,
                                         self.to_position(node, ctx),
                                         self.no_info(ctx))
        forall = self.viper.Forall(variables, triggers, implication,
                                   self.to_position(node, ctx),
                                   self.no_info(ctx))
        return dom_stmt, forall
Esempio n. 7
0
    def visit_Call(self, node: ast.Call) -> None:
        """Parse IO operation properties.

        Currently, only parses properties such as ``Terminates`` and
        ``TerminationMeasure``.
        """
        assert self._current_io_operation is not None
        assert self._current_node is not None

        body_prefix = None

        if (isinstance(node.func, ast.Name)
                and node.func.id in IO_OPERATION_PROPERTY_FUNCS):

            for child in self._current_node.body:
                if (isinstance(child, ast.Expr) and child.value == node):
                    break
            else:
                self._raise_invalid_operation('misplaced_property', node)

            operation = self._current_io_operation
            arg = node.args[0]
            if node.func.id == 'Terminates':
                if not operation.set_terminates(arg):
                    self._raise_invalid_operation('duplicate_property', node)
            elif node.func.id == 'TerminationMeasure':
                if not operation.set_termination_measure(arg):
                    self._raise_invalid_operation('duplicate_property', node)
            else:
                raise UnsupportedException(node, 'Unsupported property type.')
            self._in_property = True
            for arg in node.args:
                self.visit(arg)
            self._in_property = False
            return
        elif isinstance(
                node.func,
                ast.Name) and node.func.id in ('IOForall', 'Forall', 'Exists'):
            operation = self._current_io_operation
            assert len(node.args[1].args.args) == 1
            arg_type = self._parent.get_target(node.args[0], operation.module)
            lambda_ = node.args[1]
            body_prefix = construct_lambda_prefix(
                lambda_.lineno, getattr(lambda_, 'col_offset', None))
            for arg in lambda_.args.args:
                var = self._node_factory.create_python_var(
                    arg.arg, arg, arg_type)
                operation._io_universals.append(var)
        elif (isinstance(node.func, ast.Call)
              and isinstance(node.func.func, ast.Name)
              and node.func.func.id == 'IOExists'):
            lambda_ = node.args[0]
            arg = lambda_.args.args[0]
            body_prefix = construct_lambda_prefix(lambda_.lineno,
                                                  lambda_.col_offset)
            creator = self._node_factory.create_python_var_creator(
                arg.arg, arg, self._typeof(arg, lambda_))
            current_existentials = self._current_io_operation.get_io_existentials(
            )
            current_existentials.append(creator)
        if body_prefix:
            self._current_lambdas.append(body_prefix)
        for arg in node.args:
            self.visit(arg)
        if body_prefix:
            self._current_lambdas.pop()