Beispiel #1
0
def uint_type_cast_resolver(dtype, cast_type):
    if typeof(dtype, Ufixp):
        if cast_type.specified:
            if cast_type.width < dtype.integer:
                raise get_type_error(dtype, cast_type, [
                    f"fixed-point integer part (width '{dtype.integer}') is larger than target Uint",
                    f"FIX: to force cast to smaller Uint, cast to generic Uint first and then code() as '{repr(cast_type)}'"
                ])

            return cast_type
        elif dtype.integer <= 0:
            raise get_type_error(dtype, cast_type, [
                f"fixed-point has no integer part",
                f"FIX: to force cast to Uint, supply Uint width explicitly"
            ])
        else:
            return Uint[dtype.integer]

    if typeof(dtype, Uint):
        if not cast_type.specified:
            return dtype
        elif dtype.width > cast_type.width:
            raise get_type_error(
                dtype, cast_type,
                [f"{repr(dtype)} is larger then {repr(cast_type)}"])
        else:
            return cast_type

    raise get_type_error(dtype, cast_type)
Beispiel #2
0
def union_type_cast_resolver(dtype, cast_type):
    if (typeof(dtype, Union) and (len(cast_type.args) == 0)):
        return dtype

    if typeof(dtype, Tuple):
        if len(dtype) != 2:
            raise get_type_error(dtype, cast_type, [
                f"only Tuple with exactly 2 elements can be converted to Union"
            ])

        if typeof(cast_type, Maybe):
            if dtype.args[1].width != 1:
                raise get_type_error(dtype, cast_type, [
                    f"only Tuple with 1 bit wide second argument can be converted to Maybe"
                ])

            if not cast_type.specified:
                return Maybe[dtype.args[0]]

            data_type = cast(dtype.args[0], cast_type.types[1])

            return Maybe[data_type]

        if len(cast_type.types) != 0:
            cast_ctrl = cast_type.ctrl
            types = tuple(cast_type.types)

            if cast_type.data.width < dtype.args[0].width:
                raise get_type_error(dtype, cast_type, [
                    f"Tuple first element larger than target Union data field"
                ])

            try:
                ctrl = cast(dtype.args[1], cast_ctrl)
            except TypeError as e:
                raise TypeError(
                    f"{str(e)}\n    - when casting '{repr(dtype)}' to '{repr(cast_type)}'"
                )
        else:
            ctrl = cast(dtype.args[1], Uint)

            if ctrl.width > 6:
                raise TypeError(f'Casting to large Union with {2**ctrl.width}'
                                f' subtypes from {dtype}')

            types = (dtype.args[0], ) * (2**ctrl.width)

        res = Union[types]

        return res

    if typeof(cast_type, Maybe):
        if not (len(dtype.types) == 2 and typeof(dtype.types[0], Unit)):
            raise get_type_error(dtype, cast_type, [
                f"only Union's with with the form 'Union[Unit, Any]' can be converted to Maybe"
            ])

        return Maybe[dtype.types[1]]

    raise get_type_error(dtype, cast_type)
Beispiel #3
0
def ufixp_type_cast_resolver(dtype, cast_type):
    if typeof(dtype, Ufixp):
        if not cast_type.specified:
            return dtype

        if dtype.integer > cast_type.integer:
            raise get_type_error(dtype, cast_type, [
                f"fixed-point integer part is larger than target's integer part ('{dtype.integer}' > '{cast_type.integer})",
            ])

        if dtype.fract > cast_type.fract:
            raise get_type_error(dtype, cast_type, [
                f"fixed-point fraction part is larger than target's fraction part ('{dtype.fract}' > '{cast_type.fract})",
            ])

        return cast_type

    if typeof(dtype, Uint):
        if not cast_type.specified:
            return Ufixp[dtype.width, dtype.width]

        if dtype.width > cast_type.integer:
            raise get_type_error(dtype, cast_type, [
                f"integer is larger than fixed-point integer part ('{dtype.width}' > '{cast_type.integer})",
            ])

        return cast_type

    raise get_type_error(dtype, cast_type)
Beispiel #4
0
def tuple_type_cast_resolver(dtype, cast_type):
    if typeof(dtype, Tuple) and len(cast_type) == 0:
        return dtype

    if typeof(dtype, (Queue, Union, Tuple)):
        fields = [d for d in dtype]
    elif typeof(dtype, Array):
        fields = [dtype.data] * len(dtype)
    else:
        raise get_type_error(dtype, cast_type)

    if len(cast_type) == 0:
        return Tuple[tuple(fields)]
    elif len(cast_type) != len(fields):
        comp = 'less' if len(cast_type) < len(fields) else 'more'
        raise get_type_error(dtype, cast_type, [
            f"target Tuple has {comp} elements ({len(cast_type)}) than needed ({len(fields)})"
        ])
    else:
        try:
            cast_fields = [
                cast(dt, ct) for dt, ct in zip(fields, cast_type.args)
            ]
        except TypeError as e:
            raise TypeError(
                f"{str(e)}\n    - when casting '{repr(dtype)}' to '{repr(cast_type)}'"
            )

        if typeof(cast_type, Tuple):
            return Tuple[dict(zip(cast_type.fields, cast_fields))]
        else:
            return Tuple[tuple(cast_fields)]

    raise get_type_error(dtype, cast_type)
Beispiel #5
0
def array_type_cast_resolver(dtype, cast_type):
    if (typeof(dtype, Array) and (len(cast_type.args) == 0)):
        return dtype

    if typeof(dtype, Tuple):
        if len(cast_type.args) >= 1:
            arr_dtype = cast(dtype.args[0], cast_type.dtype)
        else:
            arr_dtype = dtype.args[0]

        if len(cast_type.args) == 2:
            if len(dtype) != len(cast_type):
                comp = 'less' if len(cast_type) < len(dtype) else 'more'
                raise get_type_error(dtype, cast_type, [
                    f"target Array has {comp} elements ({len(cast_type)}) than Tuple ({len(dtype)})"
                ])

        try:
            for t in dtype.args:
                cast(t, arr_dtype)
        except TypeError as e:
            raise TypeError(
                f"{str(e)}\n    - when casting '{repr(dtype)}' to '{repr(cast_type)}'"
            )

        return Array[arr_dtype, len(dtype)]

    if typeof(dtype, Array):
        dlen, clen = len(dtype), len(cast_type)
        if dlen != clen:
            comp = 'less' if clen < dlen else 'more'
            err_detail = [
                f"target Array has {comp} elements ({len(cast_type)}) than source ({len(dtype)})"
            ]

            if dlen % clen == 0:
                subarray = Array[dtype.data, dlen // clen]
                try:
                    subarray = cast(subarray, cast_type.data)
                    return Array[subarray, clen]
                except TypeError as e:
                    err_detail.append(str(e))

            raise get_type_error(dtype, cast_type, err_detail)

        try:
            arr_dtype = cast(dtype.data, cast_type.data)
        except TypeError as e:
            raise TypeError(
                f"{str(e)}\n    - when casting '{repr(dtype)}' to '{repr(cast_type)}'"
            )

        return Array[arr_dtype, len(dtype)]

    raise get_type_error(dtype, cast_type)
Beispiel #6
0
def int_type_cast_resolver(dtype, cast_type):
    if typeof(dtype, Fixpnumber):
        int_part = dtype.integer
        if not dtype.signed:
            int_part += 1

        if cast_type.specified:
            if not dtype.signed and cast_type.width == dtype.integer:
                raise get_type_error(dtype, cast_type, (
                    f"Int needs to be one bit larger (width {int_part}) to represent unsigned fixed-point integer part (width {dtype.integer})",
                    f"FIX: to force cast to smaller Int, cast to generic Int first and then code() as '{repr(cast_type)}'"
                ))

            elif cast_type.width < dtype.integer:
                raise get_type_error(dtype, cast_type, (
                    f"fixed-point integer part (width '{dtype.integer}') is larger than target Int",
                    f"FIX: to force cast to smaller Int, cast to generic Int first and then code() as '{repr(cast_type)}'"
                ))

            return cast_type
        elif dtype.integer <= 0:
            raise get_type_error(
                dtype, cast_type,
                (f"fixed-point has no integer part",
                 f"FIX: to force cast to Int, supply Int width explicitly"))
        else:
            return Int[int_part]

    if typeof(dtype, Integer):
        width = dtype.width
        if not dtype.signed:
            width += 1

        if not cast_type.specified:
            return Int[width]
        elif not dtype.signed and cast_type.width == dtype.width:
            raise get_type_error(dtype, cast_type, (
                f"Int needs to be one bit larger (width {width}) to represent unsigned integer (width {dtype.width})",
                f"FIX: to force cast to smaller Int, cast to generic Int first and then code() as '{repr(cast_type)}'"
            ))
        elif cast_type.width < dtype.width:
            raise get_type_error(
                dtype, cast_type,
                [f"{repr(dtype)} is larger then {repr(cast_type)}"])
        else:
            return cast_type

    raise get_type_error(dtype, cast_type)
Beispiel #7
0
def float_value_cast_resolver(val, cast_type):
    if typeof(type(val), (int, float, Number)):
        return cast_type(val)

    raise Exception(
        f'Only numbers can be converted to Float, not {val} of the type'
        f' {repr(type(val))}')
Beispiel #8
0
def signed(dtype_or_val):
    if dtype_or_val.signed:
        return dtype_or_val

    if is_type(dtype_or_val):
        if typeof(dtype_or_val, Uint):
            return cast(dtype_or_val, Int)
Beispiel #9
0
def int_value_cast_resolver(val, cast_type):
    val_type = type(val)
    if not is_type(val_type) and isinstance(val, (int, float)):
        return cast_type(int(val))

    cast_type = int_type_cast_resolver(val_type, cast_type)

    if typeof(val_type, Fixpnumber):
        if val_type.fract >= 0:
            return cast_type.decode(val.code() >> val_type.fract)
        else:
            return cast_type.decode(val.code() << (-val_type.fract))

    if typeof(val_type, Integer):
        return cast_type(val)

    raise get_value_error(val, cast_type)
Beispiel #10
0
def fixpnumber_type_cast_resolver(dtype, cast_type):
    if not typeof(dtype, Integral):
        raise get_type_error(dtype, cast_type)

    if dtype.signed:
        return fixp_type_cast_resolver(dtype, Fixp[cast_type.__args__])
    else:
        return ufixp_type_cast_resolver(dtype, Ufixp[cast_type.__args__])
Beispiel #11
0
def array_type_cast_resolver(dtype, cast_type):
    if (typeof(dtype, Array) and (len(cast_type.args) == 0)):
        return dtype

    if typeof(dtype, Tuple):
        if len(cast_type.args) >= 1:
            arr_dtype = cast(dtype.args[0], cast_type.dtype)
        else:
            arr_dtype = dtype.args[0]

        if len(cast_type.args) == 2:
            if len(dtype) != len(cast_type):
                comp = 'less' if len(cast_type) < len(dtype) else 'more'
                raise get_type_error(dtype, cast_type, [
                    f"target Array has {comp} elements ({len(cast_type)}) than Tuple ({len(dtype)})"
                ])

        try:
            for t in dtype.args:
                cast(t, arr_dtype)
        except TypeError as e:
            raise TypeError(
                f"{str(e)}\n    - when casting '{repr(dtype)}' to '{repr(cast_type)}'"
            )

        return Array[arr_dtype, len(dtype)]

    if typeof(dtype, Array):
        if len(dtype) != len(cast_type):
            comp = 'less' if len(cast_type) < len(dtype) else 'more'
            raise get_type_error(dtype, cast_type, [
                f"target Array has {comp} elements ({len(cast_type)}) than source ({len(dtype)})"
            ])

        try:
            arr_dtype = cast(dtype.data, cast_type.data)
        except TypeError as e:
            raise TypeError(
                f"{str(e)}\n    - when casting '{repr(dtype)}' to '{repr(cast_type)}'"
            )

        return Array[arr_dtype, len(dtype)]

    raise get_type_error(dtype, cast_type)
Beispiel #12
0
def integer_value_cast_resolver(val, cast_type):
    if isinstance(val, int):
        return cast_type(val)

    if typeof(type(val), Integer):
        if not cast_type.specified:
            cast_type = cast_type[val.width]

        tout_range = (1 << int(cast_type))
        val = int(val) & (tout_range - 1)

        if typeof(cast_type, Int):
            max_uint = tout_range / 2 - 1
            if val > max_uint:
                val -= tout_range

        return cast_type(val)

    raise get_value_error(val, cast_type)
Beispiel #13
0
def queue_type_cast_resolver(dtype, cast_type):
    if typeof(dtype, Queue):
        if len(cast_type.args) == 0:
            return dtype

        if dtype.lvl != cast_type.lvl:
            raise get_type_error(dtype, cast_type, [
                f"Queue level ({dtype.lvl}) must match the cast Queue lelve ({cast_type.lvl})"
            ])

        try:
            return Queue[cast(dtype.data, cast_type.data), cast_type.lvl]
        except TypeError as e:
            raise TypeError(
                f"{str(e)}\n    - when casting '{repr(dtype)}' to '{repr(cast_type)}'"
            )

    if typeof(dtype, Tuple):
        if len(dtype) != 2:
            raise get_type_error(dtype, cast_type, [
                f"only Tuple with exactly 2 elements can be converted to Queue"
            ])

        lvl = cast(dtype[1], Uint).width
        if len(cast_type.args) != 0:
            if cast_type.lvl != lvl:
                raise get_type_error(dtype, cast_type, [
                    f"second Tuple element width ({lvl}) must match Queue level ({cast_type.lvl})"
                ])

            try:
                data = cast(dtype.args[0], cast_type.data)
            except TypeError as e:
                raise TypeError(
                    f"{str(e)}\n    - when casting '{repr(dtype)}' to '{repr(cast_type)}'"
                )
        else:
            data = dtype.args[0]

        return Queue[data, lvl]

    raise get_type_error(dtype, cast_type)
Beispiel #14
0
def value_cast(val, cast_type):
    if type(val) == cast_type:
        return cast_type(val)

    for templ in value_cast_resolvers:
        if typeof(cast_type, templ):
            return value_cast_resolvers[templ](val, cast_type)

    raise ValueError(
        f"Type '{repr(cast_type)}' unsupported, cannot cast value '{val}' "
        f"of type '{repr(type(val))}'")
Beispiel #15
0
def type_cast(dtype, cast_type):

    if dtype == cast_type:
        return cast_type

    if isinstance(cast_type, str):
        return dtype

    for templ in type_cast_resolvers:
        if typeof(cast_type, templ):
            return type_cast_resolvers[templ](dtype, cast_type)

    raise TypeError(f"Cannot cast '{repr(dtype)}' to '{repr(cast_type)}'")
Beispiel #16
0
def fixp_type_cast_resolver(dtype, cast_type):
    if typeof(dtype, Fixpnumber):
        if not cast_type.specified:
            if dtype.signed:
                return dtype
            else:
                return Fixp[dtype.integer + 1, dtype.width + 1]

        int_part = dtype.integer
        if not dtype.signed:
            int_part += 1

        if int_part > cast_type.integer:
            raise get_type_error(dtype, cast_type, [
                f"needed target's integer part >= {int_part}",
            ])

        if dtype.fract > cast_type.fract:
            raise get_type_error(dtype, cast_type, [
                f"fixed-point fraction part is larger than target's fraction part ('{dtype.fract}' > '{cast_type.fract})",
            ])

        return cast_type

    if typeof(dtype, Integer):
        dtype = type_cast(dtype, Int)

        if not cast_type.specified:
            return Fixp[dtype.width, dtype.width]

        if dtype.width > cast_type.integer:
            raise get_type_error(dtype, cast_type, [
                f"integer is larger than fixed-point integer part ('{dtype.width}' > '{cast_type.integer})",
            ])

        return cast_type

    raise get_type_error(dtype, cast_type)
Beispiel #17
0
def _get_match_conds_rec(t, pat, matches):
    # Ignore type template arguments, i.e.: 'T2' in Tuple[1, 2, 3, 'T2']
    if isinstance(t, str):
        return t

    if (t == Any) or (pat == Any):
        return t

    if t == pat:
        return t

    if isinstance(pat, T):
        t = _get_match_conds_rec(t, pat.__bound__, matches)
        pat = pat.__name__

    # Did we reach the parameter name?
    if isinstance(pat, str):
        if pat in matches:
            # If the parameter name is already bound, check if two deductions
            # are same
            # if repr(t) != repr(matches[pat]) and t != Any and matches[pat] != Any:
            if t != matches[pat] and t != Any and matches[pat] != Any:
                raise TypeMatchError(
                    f'Ambiguous match for parameter "{pat}": {type_repr(t)} '
                    f"and {type_repr(matches[pat])}")
        else:
            try:
                # TODO: Should probably use globals of the string. See: Python
                # 3.10. typing.get_type_hints()
                res = eval(pat, reg['gear/type_arith'], matches)
                if t != res:
                    raise TypeMatchError(
                        f"{type_repr(t)} cannot be matched to {type_repr(res)}"
                    )
            except Exception as e:
                matches[pat] = t

        return t

    if not (isinstance(t, GenericMeta) and isinstance(pat, GenericMeta)
            and typeof(t.base, pat.base)):
        raise TypeMatchError("{} cannot be matched to {}".format(
            type_repr(t), type_repr(pat)))

    # TODO: There might be multiple levels of inheritance when the types are
    # created, maybe they are compatible base on some of their more distant
    # base classes
    if pat.args:
        if len(t.args) != len(pat.args):
            raise TypeMatchError("{} cannot be matched to {}".format(
                type_repr(t), type_repr(pat)))

        args = []
        for ta, pa in zip(t.args, pat.args):
            try:
                res = _get_match_conds_rec(ta, pa, matches)
                args.append(res)
            except TypeMatchError as e:
                raise TypeMatchError(
                    f'{str(e)}\n - when matching {repr(t)} to {repr(pat)}')

        # if hasattr(pat, '__parameters__'):
        args = {name: a for name, a in zip(pat.fields, args)}
    else:
        args = t.args

    # TODO: Revisit this Don't create a new type class when class has no
    # specified templates, so that we don't end up with multiple different
    # base class objects, that cannot be correctly tested with "issubclass"
    if not args and not t.args:
        return t
    else:
        return t.__class__(t.__name__,
                           t.__bases__,
                           dict(t.__dict__),
                           args=args)
Beispiel #18
0
def float_type_cast_resolver(dtype, cast_type):
    if typeof(dtype, Number):
        return cast_type

    raise get_type_error(dtype, cast_type)
Beispiel #19
0
def plain_int_type_cast_resolver(dtype, cast_type):
    if typeof(dtype, (Uint, Int)):
        return int

    raise get_type_error(dtype, cast_type)