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
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