Example #1
0
    def user_defined_call_semantics(self, stmt: Call, state: State,
                                    interpreter: Interpreter):
        """Forward semantics of a user-defined function/method call.

        :param stmt: call statement to be executed
        :param state: state before executing the call statement
        :return: state modified by the call statement
        """
        fname, fcfg = stmt.name, interpreter.cfgs[stmt.name]
        # add formal function parameters to the state and assign their actual values
        formal_args = interpreter.fargs[fname]
        for formal, actual in zip(formal_args, stmt.arguments):

            rhs = self.semantics(actual, state, interpreter).result
            state = state.add_variable(formal).forget_variable(formal)
            state = state.assign({formal}, rhs)

            if isinstance(actual, Call) and actual.name in interpreter.cfgs:
                _ret = VariableIdentifier(formal.typ,
                                          '{}#return'.format(actual.name))
                state = state.remove_variable(_ret)
        # add local function variables to the state
        _formal_args = set()
        for formal in formal_args:
            _formal_args.add(formal)
            # if isinstance(formal.typ, (SequenceLyraType, ContainerLyraType)):
            #     _formal_args.add(LengthIdentifier(formal))
            #     if isinstance(formal.typ, DictLyraType):
            #         _formal_args.add(KeysIdentifier(formal))
            #         _formal_args.add(ValuesIdentifier(formal))
        local_vars = set(fcfg.variables).difference(_formal_args)
        for local in local_vars:
            state = state.add_variable(local).forget_variable(local)

        fresult = interpreter.analyze(fcfg, state)  # analyze the function
        fstate = fresult.get_node_result(fcfg.out_node)[state][-1]
        state = state.bottom().join(deepcopy(fstate))

        # assign return variable
        if state.result:
            ret = VariableIdentifier(stmt.typ, '{}#return'.format(fname))
            state = state.add_variable(ret).forget_variable(ret)
            state = state.assign({ret}, state.result)
            state.result = {ret}

        # remove local function variables and formal function parameters
        for local in local_vars:
            if not local.special:
                state = state.remove_variable(local)
        for formal in formal_args:
            state = state.remove_variable(formal)

        return state
Example #2
0
    def user_defined_call_semantics(self, stmt: Call, state: State, interpreter: Interpreter):
        """Backward semantics of a user-defined function/method call.

        :param stmt: call statement to be executed
        :param state: state before executing the call statement
        :return: state modified by the call statement
        """
        fname, fcfg, _ = stmt.name, interpreter.cfgs[stmt.name], deepcopy(state)
        # analyze the function
        fresult = interpreter.analyze(fcfg, state)
        fstate = fresult.get_node_result(fcfg.in_node)[state][-1]
        state = state.bottom().join(deepcopy(fstate))
        # substitute function actual to formal parameters
        for formal, actual in zip(interpreter.fargs[fname], stmt.arguments):
            if isinstance(actual, Call) and actual.name in interpreter.cfgs:
            # TODO: right might not be a Call but just contain a Call
                state.result = {formal}
                state = self.semantics(actual, state, interpreter)
            else:
                rhs = self.semantics(actual, state, interpreter).result
                state = state.substitute({formal}, rhs)
        return state