예제 #1
0
 def range_call_semantics(self, stmt: Call, state: State) -> State:
     result = set()
     if len(stmt.arguments) == 1:
         start = Literal(IntegerLyraType(), "0")
         stops = self.semantics(stmt.arguments[0], state).result
         step = Literal(IntegerLyraType(), "1")
         for stop in stops:
             range = Range(stmt.typ, start, stop, step)
             result.add(range)
         state.result = result
         return state
     elif len(stmt.arguments) == 2:
         starts = self.semantics(stmt.arguments[0], state).result
         stops = self.semantics(stmt.arguments[1], state).result
         step = Literal(IntegerLyraType(), "1")
         for start in starts:
             for stop in stops:
                 range = Range(stmt.typ, start, stop, step)
                 result.add(range)
         state.result = result
         return state
     elif len(stmt.arguments) == 3:
         starts = self.semantics(stmt.arguments[0], state).result
         stops = self.semantics(stmt.arguments[1], state).result
         steps = self.semantics(stmt.arguments[2], state).result
         for start in starts:
             for stop in stops:
                 for step in steps:
                     range = Range(stmt.typ, start, stop, step)
                     result.add(range)
         state.result = result
         return state
     error = f"Call to {stmt.name} with unexpected number of arguments!"
     raise ValueError(error)
예제 #2
0
    def list_call_semantics(self, stmt: Call, state: State) -> State:
        """Semantics of a call to 'list'.

        :param stmt: call to 'list' to be executed
        :param state: state before executing the call statement
        :return: state modified by the call statement
        """
        def do(variable):
            if isinstance(variable.typ, StringLyraType):
                typ = ListLyraType(variable.typ)
                state.result = {VariableIdentifier(typ, variable.name)}
                return state
            elif isinstance(variable.typ, ListLyraType):
                state.result = {variable}
                return state
            elif isinstance(variable.typ, TupleLyraType):
                raise NotImplementedError(f"Conversion to list of {variable.typ} is not yet implemented!")
            elif isinstance(variable.typ, SetLyraType):
                typ = ListLyraType(variable.typ.typ)
                state.result = {VariableIdentifier(typ, variable.name)}
                return state
            elif isinstance(variable.typ, DictLyraType):
                typ = ListLyraType(variable.typ.key_typ)
                state.result = {VariableIdentifier(typ, variable.name)}
                return state
            raise TypeError(f"Unexpected type {variable.typ} for list conversion!")
        if not stmt.arguments:
            state.result = {ListDisplay(stmt.typ, list())}
            return state
        assert len(stmt.arguments) == 1  # exactly one argument is expected
        argument = stmt.arguments[0]
        if isinstance(argument, VariableAccess):
            return do(argument.variable)
        # elif isinstance(argument, SubscriptionAccess):
        #     target = argument.target
        #     if isinstance(target, VariableAccess):
        #         return do(target.variable)
        elif isinstance(argument, Call):
            if isinstance(argument.typ, StringLyraType):
                typ = ListLyraType(argument.typ)
                call = Call(argument.pp, argument.name, argument.arguments, typ)
                state.result = self.semantics(call, state).result
                return state
            elif isinstance(argument.typ, ListLyraType):
                state.result = self.semantics(argument, state).result
                return state
            elif isinstance(argument.typ, SetLyraType):
                typ = ListLyraType(argument.typ.typ)
                call = Call(argument.pp, argument.name, argument.arguments, typ)
                state.result = self.semantics(call, state).result
                return state
            elif isinstance(argument.typ, DictLyraType):
                typ = ListLyraType(argument.typ.key_typ)
                call = Call(argument.pp, argument.name, argument.arguments, typ)
                state.result = self.semantics(call, state).result
                return state
        raise NotImplementedError(f"Semantics for {stmt} is not yet implemented!")
예제 #3
0
    def tuple_call_semantics(self, stmt: Call, state: State,
                             interpreter: Interpreter) -> State:
        """Semantics of a call to 'tuple'.

        :param stmt: call to 'tuple' to be executed
        :param state: state before executing the call statement
        :return: state modified by the call statement
        """
        if not stmt.arguments:
            state.result = {TupleDisplay(stmt.typ, list())}
            return state
        assert len(stmt.arguments) == 1  # exactly one argument is expected
        argument = self.semantics(stmt.arguments[0], state, interpreter).result
        result = set()
        for expression in argument:
            if isinstance(expression.typ, StringLyraType):
                if isinstance(expression, Literal):
                    typs = [
                        deepcopy(expression.typ)
                        for _ in range(len(expression.val))
                    ]
                    typ = TupleLyraType(typs)
                    result.add(CastOperation(typ, expression))
                else:
                    error = f"Cast to tuple of {expression} is not yet implemented!"
                    raise NotImplementedError(error)
            elif isinstance(expression.typ, (ListLyraType, SetLyraType)):
                if isinstance(expression, ListDisplay):
                    typs = [
                        deepcopy(expression.typ.typ)
                        for _ in range(len(expression.items))
                    ]
                    typ = TupleLyraType(typs)
                    result.add(CastOperation(typ, expression))
                else:
                    error = f"Cast to tuple of {expression} is not yet implemented!"
                    raise NotImplementedError(error)
            elif isinstance(expression.typ, TupleLyraType):
                result.add(expression)
            elif isinstance(expression.typ, DictLyraType):
                if isinstance(expression, DictDisplay):
                    typs = [
                        deepcopy(expression.typ.key_typ)
                        for _ in range(len(expression.keys))
                    ]
                    typ = TupleLyraType(typs)
                    result.add(CastOperation(typ, expression))
                else:
                    error = f"Cast to tuple of {expression} is not yet implemented!"
                    raise NotImplementedError(error)
            else:
                error = f"Cast to list of expression {expression} with unexpected type!"
                raise ValueError(error)
        state.result = result
        return state
예제 #4
0
 def split_call_semantics(self, stmt: Call, state: State) -> State:
     if len(stmt.arguments) != 1:
         error = f"Semantics for multiple arguments of {stmt.name} is not yet implemented!"
         raise NotImplementedError(error)
     argument = self.semantics(stmt.arguments[0], state).result
     result = set()
     for arg in argument:
         assert isinstance(arg, Expression)
         if not isinstance(arg.typ, StringLyraType):
             error = f"Call to {stmt.name} of argument with unexpected type!"
             raise ValueError(error)
         typ = ListLyraType(StringLyraType())
         if isinstance(arg, Literal):  # "a b c".split() -> ["a", "b", "c"]
             items = [
                 Literal(StringLyraType(), val) for val in arg.val.split()
             ]
             result.add(ListDisplay(typ, items))
             continue
         elif isinstance(arg, VariableIdentifier):  # x.split()
             result.add(VariableIdentifier(typ, arg.name))
             continue
         elif isinstance(arg, Input):  # input().split()
             result.add(Input(typ))
             continue
         error = f"Call to {stmt.name} of unexpected argument!"
         raise ValueError(error)
     state.result = result
     return state
예제 #5
0
    def subscription_access_semantics(self, stmt: SubscriptionAccess, state: State) -> State:
        """Semantics of a subscription access.

        :param stmt: subscription access statement to be executed
        :param state: state before executing the subscription access
        :return: state modified by the subscription access
        """
        target = self.semantics(stmt.target, state).result
        key = self.semantics(stmt.key, state).result
        result = set()
        for primary, index in itertools.product(target, key):
            if isinstance(primary.typ, StringLyraType):
                subscription = Subscription(primary.typ, primary, index)
                result.add(subscription)
            elif isinstance(primary.typ, (ListLyraType, SetLyraType)):
                subscription = Subscription(primary.typ.typ, primary, index)
                result.add(subscription)
            elif isinstance(primary.typ, DictLyraType):
                subscription = Subscription(primary.typ.key_typ, primary, index)
                result.add(subscription)
            else:
                error = f"Semantics for subscription of {primary} is not yet implemented!"
                raise NotImplementedError(error)
        state.result = result
        return state
예제 #6
0
 def strip_call_semantics(self, stmt: Call, state: State,
                          interpreter: Interpreter) -> State:
     if len(stmt.arguments) != 1:
         error = f"Semantics for multiple arguments of {stmt.name} is not yet implemented!"
         raise NotImplementedError(error)
     argument = self.semantics(stmt.arguments[0], state, interpreter).result
     result = set()
     for arg in argument:
         assert isinstance(arg, Expression)
         if not isinstance(arg.typ, StringLyraType):
             error = f"Call to {stmt.name} of argument with unexpected type!"
             raise ValueError(error)
         typ = StringLyraType()
         if isinstance(arg, Input):  # input().strip()
             result.add(Input(typ))
             continue
         elif isinstance(arg, VariableIdentifier):  # x.strip()
             result.add(VariableIdentifier(typ, arg.name))
             continue
         elif isinstance(arg, Subscription):  # x[i].strip()
             result.add(Subscription(typ, arg.target, arg.key))
             continue
         error = f"Call to {stmt.name} of unexpected argument {arg}!"
         raise ValueError(error)
     state.result = result
     return state
예제 #7
0
    def _cast_call_semantics(self, stmt: Call, state: State,
                             typ: LyraType) -> State:
        """Semantics of a call to 'int' or 'bool'.

        :param stmt: call to 'int' or 'bool' to be executed
        :param state: state before executing the call statement
        :return: state modified by the call statement
        """
        if len(stmt.arguments) != 1:
            error = f"Semantics for multiple arguments of {stmt.name} is not yet implemented!"
            raise NotImplementedError(error)
        argument = self.semantics(stmt.arguments[0], state).result
        result = set()
        for expression in argument:
            if isinstance(expression, Input):
                result.add(Input(typ))
            elif isinstance(expression, Literal):
                result.add(Literal(typ, expression.val))
            elif isinstance(expression, VariableIdentifier):
                result.add(VariableIdentifier(typ, expression.name))
            elif isinstance(expression, Subscription):
                pass  # TODO
            else:
                error = f"Argument of type {expression.typ} of {stmt.name} is not yet supported!"
                raise NotImplementedError(error)
        state.result = result
        return state
예제 #8
0
    def _unary_operation(self, stmt: Call, operator: UnaryOperation.Operator,
                         state: State):
        """Semantics of a call to a unary operation.

        :param stmt: call to unary operation to be executed
        :param operator: unary operator
        :param state: state before executing the call statements
        :return: state modified by the call statement
        """
        assert len(
            stmt.arguments) == 1  # unary operations have exactly one argument
        argument = self.semantics(stmt.arguments[0], state).result
        result = set()
        if isinstance(operator, UnaryArithmeticOperation.Operator):
            for expression in argument:
                operation = UnaryArithmeticOperation(stmt.typ, operator,
                                                     expression)
                result.add(operation)
        elif isinstance(operator, UnaryBooleanOperation.Operator):
            for expression in argument:
                operation = UnaryBooleanOperation(stmt.typ, operator,
                                                  expression)
                result.add(operation)
        else:
            error = f"Semantics for unary operation {operator} is not yet implemented!"
            raise NotImplementedError(error)
        state.result = result
        return state
예제 #9
0
파일: semantics.py 프로젝트: ELowis/Lyra
    def dict_display_access_semantics(self, stmt: DictDisplayAccess,
                                      state: State) -> State:
        """Semantics of a list display access.

        :param stmt: dictionary display access statement to be executed
        :param state: state before executing the dictionary display access
        :return: state modified by the dictionary display access
        """
        k_exprs = [self.semantics(k, state).result
                   for k in stmt.keys]  # List[Set[Expression]]
        v_exprs = [self.semantics(v, state).result for v in stmt.values]

        result = set()

        if k_exprs:  # not empty
            # One "Set" of Tuples of possible key-value pairs per actual k-v-pair
            k_v_tuples = map(itertools.product, k_exprs, v_exprs)

            k_typ = next(iter(k_exprs[0])
                         ).typ  # Is there a better way to retrieve the types?
            v_typ = next(iter(v_exprs[0])).typ

            for combination in itertools.product(*k_v_tuples):
                unzip = list(
                    zip(*combination
                        ))  # to create two separate lists for keys and values
                display = DictDisplay(DictLyraType(k_typ, v_typ),
                                      list(unzip[0]), list(unzip[1]))
                result.add(display)
        else:
            # empty dict of generic type TODO: way to get specific type?
            result.add(DictDisplay(DictLyraType(LyraType(), LyraType())))
        state.result = result
        return state
예제 #10
0
    def _binary_operation(self, stmt: Call, operator: BinaryOperation.Operator,
                          state: State):
        """Semantics of a call to a binary operation.

        :param stmt: call to binary operation to be executed
        :param operator: binary operator
        :param state: state before executing the call statements
        :return: state modified by the call statement
        """
        assert len(stmt.arguments
                   ) == 2  # binary operations have exactly two arguments
        argument1 = self.semantics(stmt.arguments[0], state).result
        argument2 = self.semantics(stmt.arguments[1], state).result
        result = set()
        if isinstance(operator, BinaryArithmeticOperation.Operator):
            for left, right in itertools.product(argument1, argument2):
                operation = BinaryArithmeticOperation(stmt.typ, left, operator,
                                                      right)
                result.add(operation)
        elif isinstance(operator, BinaryComparisonOperation.Operator):
            for left, right in itertools.product(argument1, argument2):
                operation = BinaryComparisonOperation(stmt.typ, left, operator,
                                                      right)
                result.add(operation)
        elif isinstance(operator, BinaryBooleanOperation.Operator):
            for left, right in itertools.product(argument1, argument2):
                operation = BinaryBooleanOperation(stmt.typ, left, operator,
                                                   right)
                result.add(operation)
        else:
            error = f"Semantics for binary operator {operator} is not yet implemented!"
            raise NotImplementedError(error)
        state.result = result
        return state
예제 #11
0
    def variable_access_semantics(self, stmt: VariableAccess, state: State) -> State:
        """Semantics of a variable access.

        :param stmt: variable access statement to be executed
        :param state: state before executing the variable access
        :return: state modified by the variable access
        """
        state.result = {stmt.variable}
        return state
예제 #12
0
    def literal_evaluation_semantics(self, stmt: LiteralEvaluation, state: State) -> State:
        """Semantics of a literal evaluation.

        :param stmt: literal evaluation statement to be executed
        :param state: state before executing the literal evaluation
        :return: stated modified by the literal evaluation
        """
        state.result = {stmt.literal}
        return state
예제 #13
0
    def input_call_semantics(self, stmt: Call, state: State) -> State:
        """Semantics of a calls to 'input'.

        :param stmt: call to 'input' to be executed
        :param state: state before executing the call statement
        :return: state modified by the call statement
        """
        state.result = {Input(stmt.typ)}
        return state
예제 #14
0
    def dict_call_semantics(self, stmt: Call, state: State) -> State:
        """Semantics of a call to 'dict'.

        :param stmt: call to 'dict' to be executed
        :param state: state before executing the call statement
        :return: state modified by the call statement
        """
        if not stmt.arguments:
            state.result = {SetDisplay(stmt.typ, list())}
            return state
        raise NotImplementedError(f"Semantics for {stmt} is not yet implemented!")
예제 #15
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
예제 #16
0
    def set_call_semantics(self, stmt: Call, state: State,
                           interpreter: Interpreter) -> State:
        """Semantics of a call to 'set'.

        :param stmt: call to 'set' to be executed
        :param state: state before executing the call statement
        :return: state modified by the call statement
        """
        if not stmt.arguments:
            state.result = {SetDisplay(stmt.typ, list())}
            return state
        assert len(stmt.arguments) == 1  # exactly one argument is expected
        argument = self.semantics(stmt.arguments[0], state, interpreter).result
        result = set()
        for expression in argument:
            if isinstance(expression.typ, StringLyraType):
                typ = SetLyraType(expression.typ)
                result.add(CastOperation(typ, expression))
            elif isinstance(expression.typ, ListLyraType):
                typ = SetLyraType(expression.typ.typ)
                result.add(CastOperation(typ, expression))
            elif isinstance(expression.typ, TupleLyraType):
                if all(typ == expression.typ.typs[0]
                       for typ in expression.typ.typs):
                    typ = SetLyraType(expression.typ.typs[0])
                    result.add(CastOperation(typ, expression))
                else:
                    error = f"Cast to list of {expression} is not yet implemented!"
                    raise NotImplementedError(error)
            elif isinstance(expression.typ, SetLyraType):
                result.add(expression)
            elif isinstance(expression.typ, DictLyraType):
                typ = SetLyraType(expression.typ.key_typ)
                result.add(CastOperation(typ, expression))
            else:
                error = f"Cast to list of expression {expression} with unexpected type!"
                raise ValueError(error)
        state.result = result
        return state
예제 #17
0
파일: semantics.py 프로젝트: ELowis/Lyra
    def values_call_semantics(self, stmt: Call, state: State) -> State:
        """Semantics of calls to 'values'.

                        :param stmt: call to 'values' to be executed
                        :param state: state before executing the call statement
                        :return: state modified by the call statement
                        """
        if isinstance(stmt.arguments[0], VariableAccess):  # target
            state.result = {Values(stmt.typ, stmt.arguments[0].variable)}
        else:
            error = f"Semantics for values() call on non-variable {stmt.arguments[0]} is not yet "\
                    f"implemented!"
            raise NotImplementedError(error)
        return state
예제 #18
0
    def list_display_access_semantics(self, stmt: ListDisplayAccess, state: State) -> State:
        """Semantics of a list display access.

        :param stmt: list display access statement to be executed
        :param state: state before executing the list display access
        :return: state modified by the list display access
        """
        items = [self.semantics(item, state).result for item in stmt.items]
        result = set()
        for combination in itertools.product(*items):
            display = ListDisplay(stmt.typ, list(combination))
            result.add(display)
        state.result = result
        return state
예제 #19
0
    def bitxor_call_semantics(self, stmt: Call, state: State,
                              interpreter: Interpreter) -> State:
        """Semantics of calls to '^' (bitwise xor).

        :param stmt: call to '^' (bitwise xor) to be executed
        :param state: state before executing the call statement
        :return: state modified by the call statement
        """
        argument = self.semantics(stmt.arguments[0], state, interpreter).result
        result = set()
        for arg in argument:
            result.add(VariableIdentifier(stmt.typ, arg.name))
        state.result = result
        return state
예제 #20
0
    def _binary_operation(self, stmt: Call, operator: BinaryOperation.Operator, state: State):
        """Semantics of a call to a binary operation.

        :param stmt: call to binary operation to be executed
        :param operator: binary operator
        :param state: state before executing the call statements
        :return: state modified by the call statement
        """
        arguments = list()
        updated = state
        for i in range(len(stmt.arguments)):
            updated = self.semantics(stmt.arguments[i], updated)
            arguments.append(updated.result)
        assert len(arguments) >= 2      # binary operations have at least two arguments
        result = set()
        if isinstance(operator, BinaryArithmeticOperation.Operator):
            for product in itertools.product(*arguments):
                operation = product[0]
                for i in range(1, len(arguments)):
                    right = product[i]
                    operation = BinaryArithmeticOperation(stmt.typ, operation, operator, right)
                result.add(operation)
        elif isinstance(operator, BinarySequenceOperation.Operator):
            for product in itertools.product(*arguments):
                operation = product[0]
                for i in range(1, len(arguments)):
                    right = product[i]
                    operation = BinarySequenceOperation(stmt.typ, operation, operator, right)
                result.add(operation)
        elif isinstance(operator, BinaryComparisonOperation.Operator):
            for product in itertools.product(*arguments):
                operation = product[0]
                for i in range(1, len(arguments)):
                    right = product[i]
                    BCO = BinaryComparisonOperation
                    operation = BCO(stmt.typ, operation, operator, right, forloop=stmt.forloop)
                result.add(operation)
        elif isinstance(operator, BinaryBooleanOperation.Operator):
            for product in itertools.product(*arguments):
                operation = product[0]
                for i in range(1, len(arguments)):
                    right = product[i]
                    operation = BinaryBooleanOperation(stmt.typ, operation, operator, right)
                result.add(operation)
        else:
            error = f"Semantics for binary operator {operator} is not yet implemented!"
            raise NotImplementedError(error)
        state.result = result
        return state
예제 #21
0
    def len_call_semantics(self, stmt: Call, state: State) -> State:
        """Semantics of a call to 'len'.

        :param stmt: call to 'len' to be executed
        :param state: state before executing the call statement
        :return: state modified by the call statement
        """
        assert len(stmt.arguments) == 1  # unary operations have exactly one argument
        argument = stmt.arguments[0]
        if isinstance(argument, VariableAccess):
            variable = argument.variable
            state.result = {LengthIdentifier(variable)}
            return state
        error = f"Semantics for length of {argument} is not yet implemented!"
        raise NotImplementedError(error)
예제 #22
0
    def subscription_access_semantics(self, stmt: SubscriptionAccess,
                                      state: State) -> State:
        """Semantics of a subscription access.

        :param stmt: subscription access statement to be executed
        :param state: state before executing the subscription access
        :return: state modified by the subscription access
        """
        target = self.semantics(stmt.target, state).result
        key = self.semantics(stmt.key, state).result
        result = set()
        for primary, index in itertools.product(target, key):
            subscription = Subscription(primary.typ, primary, index)
            result.add(subscription)
        state.result = result
        return state
예제 #23
0
    def slicing_access_semantics(self, stmt: SlicingAccess, state: State) -> State:
        """Semantics of a slicing access.

        :param stmt: slicing access statement to be executed
        :param state: state before executing the slicing access
        :return: state modified by the slicing access
        """
        target = self.semantics(stmt.target, state).result
        lower = self.semantics(stmt.lower, state).result
        upper = self.semantics(stmt.upper, state).result if stmt.upper else {None}
        stride = self.semantics(stmt.stride, state).result if stmt.stride else {None}
        result = set()
        for primary, start, stop, step in itertools.product(target, lower, upper, stride):
            slicing = Slicing(primary.typ, primary, start, stop, step)
            result.add(slicing)
        state.result = result
        return state
예제 #24
0
 def range_call_semantics(self, stmt: Call, state: State) -> State:
     arguments = [
         self.semantics(arg, state).result.pop() for arg in stmt.arguments
     ]
     start = Literal(IntegerLyraType(), "0")
     step = Literal(IntegerLyraType(), "1")
     if len(arguments) == 1:
         end = arguments[0]
     elif len(arguments) in [2, 3]:
         start = arguments[0]
         end = arguments[1]
         if len(arguments) == 3:
             step = arguments[2]
     else:
         error = f"Semantics for range call with {len(arguments)} arguments is not implemented!"
         raise NotImplementedError(error)
     state.result = {Range(stmt.typ, start, end, step)}
     return state
예제 #25
0
    def dict_display_access_semantics(self, stmt: DictDisplayAccess, state: State) -> State:
        """Semantics of a list display access.

        :param stmt: dictionary display access statement to be executed
        :param state: state before executing the dictionary display access
        :return: state modified by the dictionary display access
        """
        keys = [self.semantics(k, state).result for k in stmt.keys]  # List[Set[Expression]]
        values = [self.semantics(v, state).result for v in stmt.values]
        result = set()
        if keys:  # not empty
            for combination in itertools.product(*map(itertools.product, keys, values)):
                unzip = list(zip(*combination))  # to create two separate lists for keys and values
                display = DictDisplay(stmt.typ, list(unzip[0]), list(unzip[1]))
                result.add(display)
        else:
            result.add(DictDisplay(stmt.typ, list(), list()))
        state.result = result
        return state
예제 #26
0
파일: semantics.py 프로젝트: ELowis/Lyra
    def tuple_display_access_semantics(self, stmt: TupleDisplayAccess,
                                       state: State) -> State:
        """Semantics of a tuple display access.

                :param stmt: tuple display access statement to be executed
                :param state: state before executing the tuple display access
                :return: state modified by the tuple display access
                """
        items = [self.semantics(item, state).result for item in stmt.items]
        result = set()
        if items:
            for combination in itertools.product(*items):
                types = [elem.typ for elem in combination]
                display = TupleDisplay(TupleLyraType(types), list(combination))
                result.add(display)
        else:
            error = f"Semantics for empty tuples not yet implemented!"  # TODO: Handle empty tuple
            raise NotImplementedError(error)
        state.result = result
        return state
예제 #27
0
파일: semantics.py 프로젝트: ELowis/Lyra
    def list_display_access_semantics(self, stmt: ListDisplayAccess,
                                      state: State) -> State:
        """Semantics of a list display access.

        :param stmt: list display access statement to be executed
        :param state: state before executing the list display access
        :return: state modified by the list display access
        """
        items = [self.semantics(item, state).result for item in stmt.items]
        result = set()
        if items:  # not empty
            for combination in itertools.product(*items):
                display = ListDisplay(ListLyraType(combination[0].typ),
                                      list(combination))
                result.add(display)
        else:
            result.add(ListDisplay(ListLyraType(
                LyraType())))  # empty list of generic type
            # TODO: way to get specific type? -> add type to display statements?
        state.result = result
        return state
예제 #28
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
예제 #29
0
    def len_call_semantics(self, stmt: Call, state: State,
                           interpreter: Interpreter) -> State:
        """Semantics of a call to 'len'.

        :param stmt: call to 'len' to be executed
        :param state: state before executing the call statement
        :return: state modified by the call statement
        """
        assert len(
            stmt.arguments) == 1  # unary operations have exactly one argument
        argument = stmt.arguments[0]
        if isinstance(argument, VariableAccess):
            variable = argument.variable
            state.result = {LengthIdentifier(variable)}
            return state
        elif isinstance(argument, ListDisplayAccess):
            items = [
                self.semantics(item, state, interpreter).result
                for item in argument.items
            ]
            result = set()
            for combination in itertools.product(*items):
                display = ListDisplay(argument.typ, list(combination))
                result.add(LengthIdentifier(display))
            state.result = result
            return state
        elif isinstance(argument, TupleDisplayAccess):
            items = [
                self.semantics(item, state, interpreter).result
                for item in argument.items
            ]
            result = set()
            for combination in itertools.product(*items):
                display = TupleDisplay(argument.typ, list(combination))
                result.add(LengthIdentifier(display))
            state.result = result
            return state
        elif isinstance(argument, SetDisplayAccess):
            items = [
                self.semantics(item, state, interpreter).result
                for item in argument.items
            ]
            result = set()
            for combination in itertools.product(*items):
                display = SetDisplay(argument.typ, list(combination))
                result.add(LengthIdentifier(display))
            state.result = result
            return state
        elif isinstance(argument, DictDisplayAccess):
            keys = [
                self.semantics(k, state, interpreter).result
                for k in argument.keys
            ]
            values = [
                self.semantics(v, state, interpreter).result
                for v in argument.values
            ]
            result = set()
            if keys:  # not empty List[Set[Expression]]
                for combination in itertools.product(
                        *map(itertools.product, keys, values)):
                    unzip = list(zip(*combination))
                    display = DictDisplay(argument.typ, list(unzip[0]),
                                          list(unzip[1]))
                    result.add(LengthIdentifier(display))
            else:
                result.add(
                    LengthIdentifier(DictDisplay(argument.typ, list(),
                                                 list())))
            state.result = result
            return state
        error = f"Semantics for length of {argument} is not yet implemented!"
        raise NotImplementedError(error)