예제 #1
0
 def translate_pythonvar_ref(self, var: PythonVar, module: PythonModule,
                             node: ast.AST, ctx: Context) -> Expr:
     # We need a context object here
     if not ctx:
         ctx = Context()
         ctx.module = module
     return self.expr_translator.translate_pythonvar_ref(var, node, ctx)
예제 #2
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
예제 #3
0
 def translate_pythonvar_decl(
         self, var: PythonVar,
         module: PythonModule) -> 'silver.ast.LocalVarDecl':
     # We need a context object here
     ctx = Context()
     ctx.module = module
     return self.expr_translator.translate_pythonvar_decl(var, ctx)
예제 #4
0
    def translate_exprs(self, nodes: List[ast.AST], function: PythonMethod,
                        ctx: Context) -> Expr:
        """
        Translates a list of nodes to a single (let-)expression if the nodes
        are only returns, assignments and if-blocks. First translates them to
        Assign- and ReturnWrappers with conditions derived from surrounding
        if-blocks (if any), then creates one big expression out of a list
        of wrappers.
        """
        # Translate to wrapper objects
        wrappers = self._translate_to_wrappers(nodes, ctx)
        self._collect_names(wrappers, function)

        # Second walk through wrappers, starting at the end. Translate all of
        # them into one big expression. Assigns become a let, returns just the
        # returned value, and if something happens in an if block, we put it
        assert not ctx.var_aliases
        previous = None
        for wrapper in reversed(wrappers):
            ctx.var_aliases = wrapper.names.copy()
            previous = self._translate_wrapper(wrapper, previous, function,
                                               ctx)

        ctx.var_aliases = {}
        return previous
예제 #5
0
파일: method.py 프로젝트: zeta1999/nagini
    def _translate_exceptional_posts(self, method: PythonMethod,
                                     err_var: 'viper.ast.LocalVar',
                                     ctx: Context) -> List[Expr]:
        """
        Translates the exceptional postconditions specified for 'method'.
        """
        ctx.obligation_context.is_translating_posts = True
        posts = []
        error = self.viper.NeCmp(err_var,
                                 self.viper.NullLit(self.no_position(ctx),
                                                    self.no_info(ctx)),
                                 self.no_position(ctx), self.no_info(ctx))
        error_type_conds = []
        error_string = '"method only raises exceptions of type{0} {1}"'.format(
            's' if len(method.declared_exceptions) > 1 else '',
            ', '.join([e.name for e in method.declared_exceptions]))
        error_type_pos = self.to_position(method.node, ctx, error_string)
        for exception in method.declared_exceptions:
            has_type = self.var_type_check(ERROR_NAME,
                                           exception,
                                           error_type_pos,
                                           ctx, inhale_exhale=False)
            error_type_conds.append(has_type)
            condition = self.viper.And(error, has_type, self.no_position(ctx),
                                       self.no_info(ctx))
            assert ctx.current_contract_exception is None
            ctx.current_contract_exception = exception
            for post, aliases in method.declared_exceptions[exception]:
                with ctx.additional_aliases(aliases):
                    stmt, expr = self.translate_expr(post, ctx, self.viper.Bool, True)
                if stmt:
                    raise InvalidProgramException(post, 'purity.violated')
                expr = self.viper.Implies(condition, expr,
                                          self.to_position(post, ctx),
                                          self.no_info(ctx))
                posts.append(expr)
            ctx.current_contract_exception = None

        error_type_cond = None
        for type in error_type_conds:
            if error_type_cond is None:
                error_type_cond = type
            else:
                error_type_cond = self.viper.Or(error_type_cond, type,
                                                error_type_pos,
                                                self.no_info(ctx))
        if error_type_cond is not None:
            posts.append(self.viper.Implies(error, error_type_cond,
                                            error_type_pos,
                                            self.no_info(ctx)))

        ctx.obligation_context.is_translating_posts = False
        return posts
예제 #6
0
 def _translate_method_body(self, method: PythonMethod, ctx: Context) -> List[Stmt]:
     body = []
     statements = method.node.body
     body_start, body_end = get_body_indices(statements)
     # Create local variables for parameters
     body.extend(self._create_local_vars_for_params(method, ctx))
     ctx.allow_statements = True
     body += flatten(
         [self.translate_stmt(stmt, ctx) for stmt in
             method.node.body[body_start:body_end]])
     ctx.allow_statements = False
     return body
예제 #7
0
파일: method.py 프로젝트: zeta1999/nagini
    def translate_function(self, func: PythonMethod,
                           ctx: Context) -> 'silver.ast.Function':
        """
        Translates a pure Python function (may or not belong to a class) to a
        Viper function
        """
        old_function = ctx.current_function
        ctx.current_function = func
        self.bind_type_vars(func, ctx)
        pos = self.to_position(func.node, ctx)
        if not func.type:
            raise InvalidProgramException(func.node, 'function.type.none')
        type = self.translate_type(func.type, ctx)
        args = self._translate_params(func, ctx)
        if func.declared_exceptions:
            raise InvalidProgramException(func.node,
                                          'function.throws.exception')
        # Create preconditions
        pres = self._translate_pres(func, ctx)
        # Create postconditions
        posts = []
        for post, aliases in func.postcondition:
            with ctx.additional_aliases(aliases):
                stmt, expr = self.translate_expr(post, ctx, self.viper.Bool)
            if stmt:
                raise InvalidProgramException(post, 'purity.violated')
            posts.append(expr)
        # Create typeof preconditions
        pres = self._create_typeof_pres(func, False, ctx) + pres
        if func.type.name not in PRIMITIVES:
            res_type_pos = self.to_position(func.node, ctx,
                                            '"return type is correct"')
            res_type = self.translate_type(func.type, ctx)
            result = self.viper.Result(res_type, res_type_pos, self.no_info(ctx))
            check = self.type_check(result, func.type, res_type_pos, ctx)
            posts = [check] + posts

        statements = func.node.body
        start, end = get_body_indices(statements)
        # Translate body
        actual_body = statements[start:end]
        if (func.contract_only or
                (len(actual_body) == 1 and isinstance(actual_body[0], ast.Expr) and
                 isinstance(actual_body[0].value, ast.Ellipsis))):
            body = None
        else:
            body = self.translate_exprs(actual_body, func, ctx)
        ctx.current_function = old_function
        name = func.sil_name
        return self.viper.Function(name, args, type, pres, posts, body,
                                   pos, self.no_info(ctx))
예제 #8
0
파일: method.py 프로젝트: zeta1999/nagini
    def _create_local_vars_for_params(self, method: PythonMethod,
                                      ctx: Context) -> List[Stmt]:
        """Creates LocalVarAssigns for each parameter."""
        assign_stmts = []
        for name, arg in method.args.items():
            arg_var = ctx.current_function.create_variable(name, arg.type,
                                                           self.translator)
            arg_assign = self.viper.LocalVarAssign(arg_var.ref(), arg.ref(),
                                                   self.no_position(ctx),
                                                   self.no_info(ctx))
            assign_stmts.append(arg_assign)
            ctx.set_alias(name, arg_var, arg)

        return assign_stmts
예제 #9
0
파일: method.py 프로젝트: zeta1999/nagini
    def translate_main_method(self, modules: List[PythonModule],
                              ctx: Context) -> List['silver.ast.Method']:
        """
        Translates the global statements of the program to a single method.
        """
        no_pos = self.no_position(ctx)
        no_info = self.no_info(ctx)

        main = self._get_main_module(modules)
        main_method, locals, stmts = self._create_main_method_setup(modules, ctx)
        method_name = main_method.sil_name

        # Translate statements in main module. When an import statement is encountered,
        # the translation will include executing the statements in the imported module.
        for stmt in main.node.body:
            stmts.extend(self.translate_stmt(stmt, ctx))

        stmts += self._method_body_postamble(main_method, ctx)
        stmts += self._create_method_epilog(main_method, ctx)

        main_locals = [local.decl for local in main_method.get_locals()
                       if not local.name.startswith('lambda')]
        for tb in main_method.try_blocks:
            main_locals.append(tb.error_var.decl)
            main_locals.append(tb.finally_var.decl)
        body = stmts
        res = self.create_method_node(ctx, method_name, [], [], [], [],
                                      main_locals + locals, body, no_pos,
                                      no_info, method=ctx.current_function)
        ctx.current_function = None
        return main_method, res
예제 #10
0
파일: method.py 프로젝트: zeta1999/nagini
    def _translate_pres(self, method: PythonMethod,
                        ctx: Context) -> List[Expr]:
        """
        Translates the preconditions specified for 'method'.
        """
        pres = []
        for pre, aliases in method.precondition:
            with ctx.additional_aliases(aliases):
                stmt, expr = self.translate_expr(pre, ctx, self.viper.Bool, True)
            if stmt:
                raise InvalidProgramException(pre, 'purity.violated')
            pres.append(expr)

        if method.cls and method.method_type is MethodType.normal:
            error_string = '"call receiver is not None"'
            pos = self.to_position(method.node, ctx, error_string)
            not_null = self.viper.NeCmp(next(iter(method.args.values())).ref(),
                                        self.viper.NullLit(
                                            self.no_position(ctx),
                                            self.no_info(ctx)),
                                        pos,
                                        self.no_info(ctx))
            pres = [not_null] + pres

        return pres
예제 #11
0
파일: method.py 프로젝트: zeta1999/nagini
    def _translate_posts(self, method: PythonMethod,
                         err_var: 'viper.ast.LocalVar',
                         ctx: Context) -> List[Expr]:
        """
        Translates the postconditions specified for 'method'.
        """
        ctx.obligation_context.is_translating_posts = True
        posts = []
        no_error = self.viper.EqCmp(err_var,
                                    self.viper.NullLit(self.no_position(ctx),
                                                       self.no_info(ctx)),
                                    self.no_position(ctx), self.no_info(ctx))
        for post, aliases in method.postcondition:
            with ctx.additional_aliases(aliases):
                stmt, expr = self.translate_expr(post, ctx, self.viper.Bool, True)
            if stmt:
                raise InvalidProgramException(post, 'purity.violated')
            if method.declared_exceptions:
                expr = self.viper.Implies(no_error, expr,
                                          self.to_position(post, ctx),
                                          self.no_info(ctx))
            posts.append(expr)

        ctx.obligation_context.is_translating_posts = False
        return posts
예제 #12
0
파일: method.py 프로젝트: zeta1999/nagini
    def translate_handler(self, handler: PythonExceptionHandler,
                          ctx: Context) -> List[Stmt]:
        """
        Creates a code block representing an exception handler, to be put at
        the end of a Viper method
        """
        label_name = ctx.get_label_name(handler.name)
        label = self.viper.Label(label_name,
                                 self.to_position(handler.node, ctx),
                                 self.no_info(ctx))
        old_var_aliases = ctx.var_aliases
        ctx.var_aliases = handler.try_block.handler_aliases
        no_position = self.no_position(ctx)
        no_info = self.no_info(ctx)
        body = []
        if handler.exception_name:
            err_var = handler.try_block.get_error_var(self.translator)
            if err_var.sil_name in ctx.var_aliases:
                err_var = ctx.var_aliases[err_var.sil_name]
            ctx.var_aliases[handler.exception_name] = err_var
            err_var.type = handler.exception

            body.append(self.set_var_defined(err_var, no_position, no_info))
        for stmt in handler.body:
            body += self.translate_stmt(stmt, ctx)
        body_block = self.translate_block(body,
                                          self.to_position(handler.node, ctx),
                                          no_info)
        if handler.try_block.finally_block:
            next = handler.try_block.finally_name
            finally_var = handler.try_block.get_finally_var(self.translator)
            if finally_var.sil_name in ctx.var_aliases:
                finally_var = ctx.var_aliases[finally_var.sil_name]
            lhs = finally_var.ref()
            rhs = self.viper.IntLit(0, no_position, no_info)
            var_set = self.viper.LocalVarAssign(lhs, rhs, no_position, no_info)
            next_var_set = [var_set]
        else:
            next = 'post_' + handler.try_block.name
            next_var_set = []
        label_name = ctx.get_label_name(next)
        goto_end = self.viper.Goto(label_name,
                                   self.to_position(handler.node, ctx),
                                   no_info)
        ctx.var_aliases = old_var_aliases
        return [label, body_block] + next_var_set + [goto_end]
예제 #13
0
파일: method.py 프로젝트: zeta1999/nagini
 def _create_method_epilog(self, method: PythonMethod,
                           ctx: Context) -> List[Stmt]:
     """
     Hook to generate the method epilog.
     """
     end_name = ctx.get_label_name(END_LABEL)
     return [self.viper.Label(end_name, self.no_position(ctx),
                              self.no_info(ctx))]
예제 #14
0
파일: method.py 프로젝트: zeta1999/nagini
 def _method_body_postamble(self, method: PythonMethod, ctx: Context) -> List[Stmt]:
     postamble = []
     end_label = ctx.get_label_name(END_LABEL)
     postamble.append(self.viper.Goto(end_label, self.no_position(ctx), self.no_info(ctx)))
     assert not ctx.var_aliases
     postamble += self._translate_try_handlers(method, ctx)
     postamble += self.add_handlers_for_inlines(ctx)
     return postamble
예제 #15
0
파일: method.py 프로젝트: zeta1999/nagini
 def bind_type_vars(self, method: PythonMethod, ctx: Context) -> None:
     """
     Binds the names of type variables of the given method and its class
     and superclasses to expressions denoting the values of said types.
     """
     ctx.bound_type_vars = {}
     # Class type variables first.
     if method.cls and method.method_type is MethodType.normal:
         cls = method.cls
         while cls:
             for name, var in cls.type_vars.items():
                 self_arg = next(iter(method.args.values())).ref()
                 literal = self.type_factory.get_ref_type_arg(self_arg,
                                                              var.target_type,
                                                              var.index, ctx)
                 ctx.bound_type_vars[(var.target_type.name, name)] = literal
             cls = cls.superclass
             if isinstance(cls, GenericType):
                 cls = cls.cls
     # Now method type variables.
     for name, var in method.type_vars.items():
         if callable(var.type_expr):
             # var.type_expr is currently the function that will create the
             # type expression when given the parameter that defines the
             # type variable (identified by var.target_node).
             for i, python_var in enumerate(method.args.values()):
                 if python_var.node is var.target_node:
                     ref = python_var.ref()
             typeof = self.type_factory.typeof(ref, ctx)
             literal = var.type_expr(self.type_factory, typeof, ctx)
             var.type_expr = literal
         else:
             literal = var.type_expr
         ctx.bound_type_vars[(var.name,)] = literal
     if method.name == 'Eval':
         # Eval uses type parameters in ways we don't usually support;
         # while translating it, we're treating the type parameter V as type
         # object.
         object_type = ctx.module.global_module.classes[OBJECT_TYPE]
         literal = self.type_factory.translate_type_literal(object_type,
                                                            self.no_position(ctx), ctx)
         ctx.bound_type_vars[('V',)] = literal
예제 #16
0
파일: method.py 프로젝트: zeta1999/nagini
    def _create_main_method_setup(self, modules: List[PythonModule],
                                  ctx: Context) -> Tuple[PythonMethod, List[VarDecl], List[Stmt]]:
        main = self._get_main_module(modules)
        locals, init_stmts = self._initialize_main_state(modules, main, ctx)

        # Create artificial main PythonMethod that contains the execution of global
        # statements.
        ctx.current_class = None
        method_name = ctx.module.get_fresh_name('main')
        main_method = PythonMethod(MAIN_METHOD_NAME, main, None, main, False, False,
                                   main.node_factory)
        main_method._module = main
        ctx.current_function = main_method
        ctx.current_function.try_blocks = main.try_blocks
        ctx.current_function.labels = main.labels
        ctx.current_function.precondition = main.precondition
        ctx.current_function.postcondition = main.postcondition
        ctx.current_function.loop_invariants = main.loop_invariants
        ctx.current_function.process(method_name, self.translator)
        ctx.module = main
        return main_method, locals, init_stmts
예제 #17
0
    def translate_predicate(self, pred: PythonMethod,
                            ctx: Context) -> 'ast.silver.Predicate':
        """
        Translates pred to a Silver predicate.
        """
        if not pred.type or pred.type.name != BOOL_TYPE:
            raise InvalidProgramException(pred.node, 'invalid.predicate')
        assert ctx.current_function is None
        ctx.current_function = pred
        args = []
        arg_types = self.viper.TrueLit(self.no_position(ctx),
                                       self.no_info(ctx))
        for name, arg in pred.args.items():
            args.append(arg.decl)
            arg_type = self.type_check(arg.ref(), arg.type,
                                       self.no_position(ctx), ctx)
            arg_types = self.viper.And(arg_types, arg_type,
                                       self.no_position(ctx),
                                       self.no_info(ctx))
        if len(pred.node.body) != 1:
            raise InvalidProgramException(pred.node, 'invalid.predicate')

        content = pred.node.body[0]
        if isinstance(content, ast.Return):
            content = content.value
        stmt, body = self.translate_expr(content,
                                         ctx,
                                         impure=True,
                                         target_type=self.viper.Bool)
        if stmt:
            raise InvalidProgramException(pred.node, 'invalid.predicate')
        body = self.viper.And(arg_types, body, self.no_position(ctx),
                              self.no_info(ctx))
        ctx.current_function = None
        return self.viper.Predicate(pred.sil_name, args, body,
                                    self.to_position(pred.node, ctx),
                                    self.no_info(ctx))
예제 #18
0
 def translate_type(self, cls: PythonClass,
                    ctx: Context) -> 'silver.ast.Type':
     """
     Translates the given type to the corresponding Viper type (Int, Ref, ..)
     """
     if isinstance(cls, SilverType):
         return cls.type
     elif cls.name == CALLABLE_TYPE:
         ctx.are_function_constants_used = True
         return self.viper.function_domain_type()
     elif cls.name in PRIMITIVES:
         cls = cls.try_box()
         return self.builtins['builtins.' + cls.name]
     elif cls.name == 'type':
         return self.type_factory.type_type()
     else:
         return self.viper.Ref
예제 #19
0
 def translate_program(self,
                       modules: List[PythonModule],
                       sil_progs: List,
                       selected: Set[str] = None,
                       ignore_global: bool = False,
                       arp: bool = False,
                       sif=False) -> 'silver.ast.Program':
     ctx = Context()
     ctx.sif = sif
     ctx.current_class = None
     ctx.current_function = None
     ctx.module = modules[0]
     ctx.arp = arp
     return self.prog_translator.translate_program(modules, sil_progs, ctx,
                                                   selected, ignore_global)
예제 #20
0
    def translate_main_method(self, modules: List[PythonModule],
                              ctx: Context) -> List[Method]:
        no_pos = self.no_position(ctx)
        no_info = self.no_info(ctx)

        main = self._get_main_module(modules)
        main_method, locals, stmts = self._create_main_method_setup(
            modules, ctx)
        method_name = main_method.sil_name

        # Create an error variable
        error_var = self.create_method_error_var(ctx)
        main_method.error_var = error_var
        locals.append(error_var.decl)
        stmts.append(
            self.viper.LocalVarAssign(error_var.ref(),
                                      self.viper.NullLit(no_pos, no_info),
                                      no_pos, no_info))

        # Translate statements in main module. When an import statement is encountered,
        # the translation will include executing the statements in the imported module.
        for stmt in main.node.body:
            stmts.extend(self.translate_stmt(stmt, ctx))

        stmts += self._method_body_postamble(main_method, ctx)
        stmts += self._create_method_epilog(main_method, ctx)

        main_locals = [
            local.decl for local in main_method.get_locals()
            if not local.name.startswith('lambda')
        ]
        res = self.create_method_node(ctx,
                                      method_name, [], [], [], [],
                                      main_locals + locals,
                                      stmts,
                                      no_pos,
                                      no_info,
                                      method=ctx.current_function)
        ctx.current_function = None
        return main_method, res
예제 #21
0
파일: method.py 프로젝트: zeta1999/nagini
    def translate_method(self, method: PythonMethod,
                         ctx: Context) -> 'silver.ast.Method':
        """
        Translates an impure Python function (may or not belong to a class) to
        a Viper method
        """
        old_function = ctx.current_function
        ctx.current_function = method
        args = self._translate_params(method, ctx)
        self.bind_type_vars(method, ctx)

        results = [res.decl for res in method.get_results()]
        error_var = self.create_method_error_var(ctx)
        error_var_decl = error_var.decl
        error_var_ref = error_var.ref()
        method.error_var = error_var
        pres, posts = self.extract_contract(method, ERROR_NAME, False, ctx)
        if method.cls and method.name == '__init__':
            init_pres = self._create_init_pres(method, ctx)
            pres = init_pres + pres
        if method.declared_exceptions:
            results.append(error_var_decl)

        # Translate body
        body = []
        no_pos = self.no_position(ctx)
        no_info = self.no_info(ctx)
        if method.cls and method.method_type == MethodType.normal:
            body.append(self._check_self_type(method, ctx))
        if method.type:
            # Assign null as the default return value to the return variable.
            assign_none = self.viper.LocalVarAssign(method.result.ref(),
                                                    self.viper.NullLit(no_pos,
                                                                       no_info),
                                                    no_pos, no_info)
            body.append(assign_none)
        if method.contract_only:
            false = self.viper.FalseLit(self.no_position(ctx),
                                        self.no_info(ctx))
            assume_false = self.viper.Inhale(false, self.no_position(ctx),
                                             self.no_info(ctx))
            body.append(assume_false)
            locals = []
        else:
            body.append(self.viper.LocalVarAssign(error_var_ref,
                self.viper.NullLit(self.no_position(ctx),
                                    self.no_info(ctx)),
                self.no_position(ctx), self.no_info(ctx)))
            if method.declared_exceptions:
                locals = []
            else:
                locals = [error_var_decl]
            body += self._translate_method_body(method, ctx)
            for arg in method.get_args():
                ctx.remove_alias(arg.name)
            body += self._method_body_postamble(method, ctx)
            locals += [local.decl for local in method.get_locals()
                       if not local.name.startswith('lambda')]
            body += self._create_method_epilog(method, ctx)
        name = method.sil_name
        nodes = self.create_method_node(
            ctx, name, args, results, pres, posts, locals, body,
            self.to_position(method.node, ctx), self.no_info(ctx),
            method=method)
        ctx.current_function = old_function
        return nodes
예제 #22
0
    def translate_predicate_family(
        self, root: PythonMethod, preds: List[PythonMethod], ctx: Context
    ) -> Tuple[List['ast.silver.Predicate'], List['ast.silver.Method']]:
        """
        Translates the methods in preds, whose root (which they all override)
        is root, to a family-predicate in Silver.
        """
        no_info = self.no_info(ctx)
        dependencies = {}
        for pred in preds:
            value = {pred.overrides} if pred.overrides else set()
            dependencies[pred] = value
        sorted = toposort_flatten(dependencies, False)

        name = root.sil_name
        args = []
        self_var_ref = root.args[next(iter(root.args))].ref()
        true_lit = self.viper.TrueLit(self.no_position(ctx), self.no_info(ctx))
        arg_types = true_lit
        self.bind_type_vars(root, ctx)
        for arg in root.args.values():
            args.append(arg.decl)
            arg_type = self.type_check(arg.ref(), arg.type,
                                       self.no_position(ctx), ctx)
            arg_types = self.viper.And(arg_types, arg_type,
                                       self.no_position(ctx),
                                       self.no_info(ctx))
        unknown_type_condition = true_lit
        self_framing_check_methods = []

        body = None
        assert not ctx.var_aliases
        for instance in sorted:
            ctx.var_aliases = {}
            assert not ctx.current_function
            if instance.type.name != BOOL_TYPE:
                raise InvalidProgramException(instance.node,
                                              'invalid.predicate')
            ctx.current_function = instance
            ctx.module = instance.module
            self.bind_type_vars(instance, ctx)
            # Replace variables in instance by variables in root, since we use the
            # parameter names from root.
            for root_name, current_name in zip(root.args.keys(),
                                               instance.args.keys()):
                root_var = root.args[root_name]
                # For the receiver parameter, we need it to have the same sil_name as
                # that of the root, but the type of the current instance when translating
                # it, otherwise some fields/functions/predicates may not be found.
                if root_name == next(iter(root.args.keys())):
                    root_var = copy.copy(root_var)
                    root_var.type = instance.cls
                ctx.set_alias(current_name, root_var)
            actual_body_start = 0
            while (actual_body_start < len(instance.node.body) and isinstance(
                    instance.node.body[actual_body_start], ast.Expr)
                   and isinstance(instance.node.body[actual_body_start].value,
                                  ast.Str)):
                actual_body_start += 1
            if len(instance.node.body[actual_body_start:]) != 1:
                raise InvalidProgramException(instance.node,
                                              'invalid.predicate')
            content = instance.node.body[actual_body_start]
            if isinstance(content, ast.Return):
                content = content.value

            stmt, current = self.translate_expr(content,
                                                ctx,
                                                impure=True,
                                                target_type=self.viper.Bool)
            if stmt:
                raise InvalidProgramException(instance.node,
                                              'invalid.predicate')
            instance_pos = self.to_position(instance.node, ctx)
            has_type = self.type_factory.type_check(self_var_ref, instance.cls,
                                                    instance_pos, ctx)
            implication = self.viper.Implies(has_type, current, instance_pos,
                                             no_info)
            self_var_type_expr = self.type_factory.typeof(self_var_ref, ctx)
            instance_type = self.type_factory.translate_type_literal(
                instance.cls, instance_pos, ctx, alias=self_var_type_expr)
            type_not_instance = self.viper.NeCmp(self_var_type_expr,
                                                 instance_type, instance_pos,
                                                 no_info)
            unknown_type_condition = self.viper.And(unknown_type_condition,
                                                    type_not_instance,
                                                    instance_pos, no_info)
            ctx.current_function = None
            if body:
                body = self.viper.And(body, implication,
                                      self.to_position(root.node, ctx),
                                      no_info)
            else:
                body = implication
            self_frame_method_name = root.module.get_fresh_name(root.name +
                                                                '_' +
                                                                instance.name +
                                                                'frame_check')
            pos_with_rule = self.to_position(
                instance.node, ctx, rules=rules.PRED_FAM_MEMBER_NOT_FRAMED)
            current_with_rule = self.viper.And(true_lit, current,
                                               pos_with_rule, no_info)
            self_frame_method = self.viper.Method(
                self_frame_method_name, args, [],
                [arg_types, has_type, current_with_rule], [], [], None,
                self.to_position(root.node, ctx), no_info)
            self_framing_check_methods.append(self_frame_method)
            # Dirty hack to artificially create a dependency from this predicate to its well-formedness check;
            # the call is never used, but the creation of the call while translating the predicate will be tracked.
            self.viper.MethodCall(self_frame_method_name, [], [],
                                  self.to_position(root.node, ctx), no_info)
        root_pos = self.to_position(root.node, ctx)
        all_preds = []
        if not (root.name == 'invariant' and root.cls.name == 'Lock'):
            root_pos_with_rule = self.to_position(
                root.node, ctx, rules=rules.PRED_FAM_FOLD_UNKNOWN_RECEIVER)
            rest_pred_name = root.module.get_fresh_name(root.name +
                                                        '_abstract_rest')
            rest_pred = self.viper.Predicate(rest_pred_name, args, None,
                                             root_pos, no_info)
            all_preds.append(rest_pred)
            rest_pred_acc = self.viper.PredicateAccess(
                [arg.localVar() for arg in args], rest_pred_name,
                root_pos_with_rule, no_info)
            rest_pred_acc_pred = self.viper.PredicateAccessPredicate(
                rest_pred_acc, self.viper.FullPerm(root_pos_with_rule,
                                                   no_info),
                root_pos_with_rule, no_info)
            body = self.viper.And(
                body,
                self.viper.Implies(unknown_type_condition, rest_pred_acc_pred,
                                   root_pos_with_rule, no_info),
                root_pos_with_rule, no_info)
        ctx.var_aliases = {}
        body = self.viper.And(arg_types, body, root_pos, no_info)
        family_pred = self.viper.Predicate(name, args, body, root_pos, no_info)
        all_preds.append(family_pred)
        return all_preds, self_framing_check_methods
예제 #23
0
파일: method.py 프로젝트: zeta1999/nagini
    def translate_finally(self, block: PythonTryBlock,
                          ctx: Context) -> List[Stmt]:
        """
        Creates a code block representing the finally-block belonging to block,
        to be put at the end of a Viper method.
        """
        pos = self.to_position(block.node, ctx)
        info = self.no_info(ctx)
        label_name = ctx.get_label_name(block.finally_name)
        label = self.viper.Label(label_name,
                                 self.to_position(block.node, ctx),
                                 self.no_info(ctx))
        loop = get_parent_of_type(block.node, (ast.While, ast.For))
        body = [label]
        if block.finally_block:
            for stmt in block.finally_block:
                body += self.translate_stmt(stmt, ctx)
        else:
            # With-block
            ctx_type = self.get_type(block.with_item.context_expr, ctx)
            ctx_var = block.with_var
            exit_type = ctx_type.get_method('__exit__').type
            exit_res = ctx.current_function.create_variable('exit_res',
                                                            exit_type,
                                                            self.translator)

            type_class = ctx.module.global_module.classes['type']
            exception_class = ctx.module.global_module.classes['Exception']
            tb_class = ctx.module.global_module.classes['traceback']
            # The __exit__ method takes three arguments: type, value and
            # traceback.
            type_var = ctx.actual_function.create_variable('t', type_class,
                                                           self.translator)
            value_var = ctx.actual_function.create_variable('e',
                                                            exception_class,
                                                            self.translator)
            traceback_var = ctx.actual_function.create_variable('tb',
                                                                tb_class,
                                                                self.translator)
            body.append(self._assign_exit_vars(block, type_var, value_var,
                                               traceback_var, pos, ctx))
            exit_call = self.get_method_call(ctx_type, '__exit__',
                                             [ctx_var.ref(), type_var.ref(),
                                              value_var.ref(),
                                              traceback_var.ref()],
                                             [ctx_type, None, None, None],
                                             [exit_res.ref()],
                                             block.with_item.context_expr, ctx)
            body.extend(exit_call)
        finally_var = block.get_finally_var(self.translator)
        if finally_var.sil_name in ctx.var_aliases:
            finally_var = ctx.var_aliases[finally_var.sil_name]
        tries = get_surrounding_try_blocks(ctx.actual_function.try_blocks,
                                           block.node)
        tries_in_same_loop = []
        if loop is not None:
            tries_in_same_loop = [t for t in tries if get_parent_of_type(t.node, (ast.While, ast.For)) is loop]

        post_label = ctx.get_label_name(block.post_name)
        goto_post = self.viper.Goto(post_label, pos, info)
        end_label = ctx.get_label_name(END_LABEL)
        goto_end = self.viper.Goto(end_label, pos, info)
        empty_stmt = self.translate_block([], pos, info)

        except_block = []
        return_block = []
        for current in tries:
            if not return_block and current.finally_block:
                # Propagate finally var value
                var_next = current.get_finally_var(self.translator)
                if var_next.sil_name in ctx.var_aliases:
                    var_next = ctx.var_aliases[var_next.sil_name]
                next_assign = self.viper.LocalVarAssign(var_next.ref(),
                                                        finally_var.ref(),
                                                        pos, info)
                # Goto finally block
                next_label = ctx.get_label_name(current.finally_name)
                goto_next = self.viper.Goto(next_label, pos, info)
                return_block = [next_assign, goto_next]
            for handler in current.handlers:
                # If handler applies,
                # goto handler
                err_var = block.get_error_var(self.translator)
                if err_var.sil_name in ctx.var_aliases:
                    err_var = ctx.var_aliases[err_var.sil_name]
                condition = self.var_type_check(err_var.sil_name,
                                                handler.exception,
                                                self.to_position(handler.node,
                                                                 ctx),
                                                ctx, inhale_exhale=False)
                label_name = ctx.get_label_name(handler.name)
                goto = self.viper.Goto(label_name, pos, info)
                if_handler = self.viper.If(condition, goto, empty_stmt, pos,
                                           info)
                except_block.append(if_handler)
            if current.finally_block:
                # Propagate finally var value
                # Goto finally block
                except_block += return_block
                break
        break_block = []
        for current in tries_in_same_loop:
            if not break_block and current.finally_block:
                # Propagate finally var value
                var_next = current.get_finally_var(self.translator)
                if var_next.sil_name in ctx.var_aliases:
                    var_next = ctx.var_aliases[var_next.sil_name]
                next_assign = self.viper.LocalVarAssign(var_next.ref(),
                                                        finally_var.ref(),
                                                        pos, info)
                # Goto finally block
                next_label = ctx.get_label_name(current.finally_name)
                goto_next = self.viper.Goto(next_label, pos, info)
                break_block = [next_assign, goto_next]
                continue_block = [next_assign, goto_next]
        if not return_block:
            return_block = [goto_end]
        if loop and not break_block:
            goto_break = self.viper.Goto(loop.post_label, pos, info)
            goto_continue = self.viper.Goto(loop.end_label, pos, info)
            break_block = [goto_break]
            continue_block = [goto_continue]
        if ctx.actual_function.declared_exceptions:
            # Assign error to error output var
            error_var = ctx.error_var.ref()
            block_error_var = block.get_error_var(self.translator)
            if block_error_var.sil_name in ctx.var_aliases:
                block_error_var = ctx.var_aliases[block_error_var.sil_name]
            assign = self.viper.LocalVarAssign(
                error_var, block_error_var.ref(), pos, info)
            except_block.append(assign)
            except_block.append(goto_end)
        else:
            error_string = '"method raises no exceptions"'
            error_pos = self.to_position(block.node, ctx, error_string)
            false = self.viper.FalseLit(error_pos, info)
            assert_false = self.viper.Exhale(false, error_pos, info)
            except_block.append(assert_false)
            except_block.append(goto_end)
        except_block = self.translate_block(except_block, pos, info)
        return_block = self.translate_block(return_block, pos, info)
        if loop:
            break_block = self.translate_block(break_block, pos, info)
            continue_block = self.translate_block(continue_block, pos, info)

        number_one = self.viper.IntLit(1, pos, info)
        number_two = self.viper.IntLit(2, pos, info)
        number_three = self.viper.IntLit(3, pos, info)
        number_four = self.viper.IntLit(4, pos, info)

        is_one = self.viper.EqCmp(finally_var.ref(), number_one, pos, info)
        is_two = self.viper.EqCmp(finally_var.ref(), number_two, pos, info)
        is_three = self.viper.EqCmp(finally_var.ref(), number_three, pos, info)
        is_four = self.viper.EqCmp(finally_var.ref(), number_four, pos, info)

        if_return = self.viper.If(is_one, return_block, goto_post, pos,
                                  info)
        if_except = self.viper.If(is_two, except_block, if_return, pos,
                                  info)
        top_level_if = if_except
        if loop is not None:
            if_break = self.viper.If(is_three, break_block, if_except, pos, info)
            if_continue = self.viper.If(is_four, continue_block, if_break, pos, info)
            top_level_if = if_continue
        body += [top_level_if]
        return body
예제 #24
0
    def translate_predicate_family(self, root: PythonMethod,
                                   preds: List[PythonMethod],
                                   ctx: Context) -> 'ast.silver.Predicate':
        """
        Translates the methods in preds, whose root (which they all override)
        is root, to a family-predicate in Silver.
        """
        dependencies = {}
        for pred in preds:
            value = {pred.overrides} if pred.overrides else set()
            dependencies[pred] = value
        sorted = toposort_flatten(dependencies, False)

        name = root.sil_name
        args = []
        self_var_ref = root.args[next(iter(root.args))].ref()
        arg_types = self.viper.TrueLit(self.no_position(ctx),
                                       self.no_info(ctx))
        self.bind_type_vars(root, ctx)
        for arg in root.args.values():
            args.append(arg.decl)
            arg_type = self.type_check(arg.ref(), arg.type,
                                       self.no_position(ctx), ctx)
            arg_types = self.viper.And(arg_types, arg_type,
                                       self.no_position(ctx),
                                       self.no_info(ctx))
        body = None
        assert not ctx.var_aliases
        for instance in sorted:
            ctx.var_aliases = {}
            assert not ctx.current_function
            if instance.type.name != BOOL_TYPE:
                raise InvalidProgramException(instance.node,
                                              'invalid.predicate')
            ctx.current_function = instance
            ctx.module = instance.module
            self.bind_type_vars(instance, ctx)
            # Replace variables in instance by variables in root, since we use the
            # parameter names from root.
            for root_name, current_name in zip(root.args.keys(),
                                               instance.args.keys()):
                root_var = root.args[root_name]
                # For the receiver parameter, we need it to have the same sil_name as
                # that of the root, but the type of the current instance when translating
                # it, otherwise some fields/functions/predicates may not be found.
                if root_name == next(iter(root.args.keys())):
                    root_var = copy.copy(root_var)
                    root_var.type = instance.cls
                ctx.set_alias(current_name, root_var)
            actual_body_start = 0
            while (actual_body_start < len(instance.node.body) and isinstance(
                    instance.node.body[actual_body_start], ast.Expr)
                   and isinstance(instance.node.body[actual_body_start].value,
                                  ast.Str)):
                actual_body_start += 1
            if len(instance.node.body[actual_body_start:]) != 1:
                raise InvalidProgramException(instance.node,
                                              'invalid.predicate')
            content = instance.node.body[actual_body_start]
            if isinstance(content, ast.Return):
                content = content.value

            stmt, current = self.translate_expr(content,
                                                ctx,
                                                impure=True,
                                                target_type=self.viper.Bool)
            if stmt:
                raise InvalidProgramException(instance.node,
                                              'invalid.predicate')
            has_type = self.type_factory.type_check(
                self_var_ref, instance.cls,
                self.to_position(instance.node, ctx), ctx)
            implication = self.viper.Implies(
                has_type, current, self.to_position(instance.node, ctx),
                self.no_info(ctx))
            ctx.current_function = None
            if body:
                body = self.viper.And(body, implication,
                                      self.to_position(root.node, ctx),
                                      self.no_info(ctx))
            else:
                body = implication
        ctx.var_aliases = {}
        body = self.viper.And(arg_types, body, self.no_position(ctx),
                              self.no_info(ctx))
        return self.viper.Predicate(name, args, body,
                                    self.to_position(root.node, ctx),
                                    self.no_info(ctx))
예제 #25
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