def _create_termination_check(self, operation: PythonIOOperation, ctx: Context) -> Method: """Create a termination check.""" assert not ctx.current_function ctx.current_function = operation name = ctx.module.get_fresh_name(operation.sil_name + '__termination_check') if operation.sil_name not in self.viper.used_names_sets: self.viper.used_names_sets[operation.sil_name] = set() self.viper.used_names_sets[operation.sil_name].add(name) parameters = [ parameter.decl for parameter in operation.get_parameters() ] locals = [v.decl for v in operation._io_universals] info = self.no_info(ctx) pos = self.to_position(operation.get_termination_measure(), ctx) local_type_assumptions = [ self.viper.Inhale( self.type_check(v.ref(), v.type, pos, ctx, False), pos, info) for v in operation._io_universals ] statement, termination_condition = self.translate_expr( operation.get_terminates(), ctx, target_type=self.viper.Bool) assert not statement statement, termination_measure = self.translate_expr( operation.get_termination_measure(), ctx, target_type=self.viper.Int) assert not statement generator = TerminationCheckGenerator( self, ctx, termination_condition, termination_measure, operation.get_termination_measure()) if operation.is_basic(): checks = generator.create_checks() else: checks = generator.create_checks(operation.get_body()) body = self.translate_block(local_type_assumptions + checks, pos, info) pres = self._create_typeof_pres(operation.get_parameters(), ctx) ctx.current_function = None result = self.viper.Method(name=name, args=parameters, returns=[], pres=pres, posts=[], locals=locals, body=body, position=self.no_position(ctx), info=info) return result
def _translate_defining_getters(self, main_operation: PythonIOOperation, ctx: Context) -> None: """Translate defining getter instances of existential variables.""" assert not main_operation.is_basic() assert ctx.current_function is None ctx.current_function = main_operation existentials = main_operation.get_io_existentials() existentials.sort(key=lambda var: var.defining_order) for existential in existentials: node, result = existential.get_defining_info() getter = self.create_result_getter(node, result, ctx) existential.set_existential_ref(getter) ctx.current_function = None
def _create_termination_check(self, operation: PythonIOOperation, ctx: Context) -> Method: """Create a termination check.""" assert not ctx.current_function ctx.current_function = operation name = ctx.module.get_fresh_name(operation.sil_name + '__termination_check') parameters = [ parameter.decl for parameter in operation.get_parameters() ] statement, termination_condition = self.translate_expr( operation.get_terminates(), ctx, target_type=self.viper.Bool) assert not statement statement, termination_measure = self.translate_expr( operation.get_termination_measure(), ctx, target_type=self.viper.Int) assert not statement generator = TerminationCheckGenerator( self, ctx, termination_condition, termination_measure, operation.get_termination_measure()) if operation.is_basic(): checks = generator.create_checks() else: checks = generator.create_checks(operation.get_body()) info = self.no_info(ctx) position = self.to_position(operation.get_termination_measure(), ctx) body = self.translate_block(checks, position, info) pres = self._create_typeof_pres(operation.get_parameters(), ctx) ctx.current_function = None result = self.viper.Method(name=name, args=parameters, returns=[], pres=pres, posts=[], locals=[], body=body, position=self.no_position(ctx), info=info) return result
def set_up_io_operation_input_aliases(self, operation: PythonIOOperation, node: ast.Call, ctx: Context) -> List[str]: """Set up aliases from operation's parameters to its arguments.""" aliases = [] parameters = operation.get_parameters() py_args = node.args[:len(parameters)] sil_args = self.translate_args(py_args, parameters, ctx) for parameter, py_arg, sil_arg in zip(parameters, py_args, sil_args): var_type = self.get_type(py_arg, ctx).try_unbox() var = PythonIOExistentialVar(parameter.name, py_arg, var_type) var.set_ref(sil_arg, None) ctx.set_alias(parameter.name, var) aliases.append(parameter.name) return aliases
def add_handlers_for_inlines(self, ctx: Context) -> List[Stmt]: stmts = [] old_var_valiases = ctx.var_aliases old_lbl_aliases = ctx.label_aliases for (added_method, var_aliases, lbl_aliases) in ctx.added_handlers: ctx.var_aliases = var_aliases ctx.label_aliases = lbl_aliases ctx.inlined_calls.append(added_method) for block in added_method.try_blocks: for handler in block.handlers: stmts += self.translate_handler(handler, ctx) if block.else_block: stmts += self.translate_handler(block.else_block, ctx) if block.finally_block: stmts += self.translate_finally(block, ctx) ctx.inlined_calls.remove(added_method) ctx.added_handlers = [] ctx.var_aliases = old_var_valiases ctx.label_aliases = old_lbl_aliases return stmts
def create_method_node( # pylint: disable=too-many-arguments,too-many-locals self, ctx: Context, name: str, original_args: List[VarDecl], returns: List[VarDecl], pres: List[Expr], posts: List[Expr], local_vars: List[VarDecl], body: List[Stmt], position: Position, info: Info, method: PythonMethod = None, overriding_check: bool = False) -> Method: """Construct method AST node with additional obligation stuff.""" if method is None: method = find_method_by_sil_name(ctx, name) if method is None: # Assume that this is a method that is never called from # Python and, as a result, does not need obligation stuff. return self.viper.Method(name, original_args, returns, pres, posts, local_vars, body, position, info) assert (ctx.current_function is None or ctx.current_function == method) old_method = ctx.current_function ctx.current_function = method obligation_method = ObligationMethod(name, original_args, returns, pres, posts, local_vars, body) constructor = ObligationMethodNodeConstructor(obligation_method, method, self, ctx, self._obligation_manager, position, info, overriding_check) constructor.add_obligations() node = constructor.construct_node() ctx.current_function = old_method return node
def get_fresh_int_lit(self, ctx: Context) -> Expr: """ Returns an integer literal with a fresh value. """ return self.viper.IntLit(ctx.get_fresh_int(), self.no_position(ctx), self.no_info(ctx))