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 assignment_semantics(self, stmt: Assignment, state: State) -> State: """Forward semantics of an assignment. :param stmt: assignment statement to be executed :param state: state before executing the assignment :return: state modified by the assignment """ lhs = self.semantics(stmt.left, state).result # lhs evaluation rhs = self.semantics(stmt.right, state).result # rhs evaluation return state.assign(lhs, rhs)
def append_call_semantics(self, stmt: Call, state: State) -> State: assert len(stmt.arguments) == 2 targets = self.semantics(stmt.arguments[0], state).result op = BinarySequenceOperation.Operator.Concat values = self.semantics(stmt.arguments[1], state).result rhs = set() for target in targets: for value in values: display = ListDisplay(ListLyraType(value.typ), [value]) rhs.add( BinarySequenceOperation(target.typ, target, op, display)) return state.assign(targets, rhs)