def resolve_cast_func(opexp, dtype): if opexp.dtype == dtype: return opexp for templ in resolvers: try: get_match_conds(dtype, templ) return resolvers[templ](opexp, dtype) except TypeMatchError: continue return ir.CastExpr(operand=opexp, cast_to=cast(opexp.dtype, dtype))
def test_tuple_multi_lvl_field_names(): type_ = Tuple['field1':1, 'field2':Uint[2], 'field3':3] templ = Tuple[{'field1': 1, 'field2': Integer['N1'], 'field3': 3}] match, res = get_match_conds(type_, templ) assert match == {'N1': 2} assert res == type_ assert res.fields == ('field1', 'field2', 'field3')
def test_tuple_multi_lvl_single_template(): type_ = Tuple[1, Uint[2], 3] templ = Tuple[1, T('Ti', Uint['T1']), 3] match, res = get_match_conds(type_, templ) assert match == {'T1': 2, 'Ti': Uint[2]} assert res == type_
def test_tuple_subst(): type_ = Tuple[1, Uint[2], 3] templ = Tuple[1, 'T1', 3] templ = templ[T('T2', Integer['N1'])] match, res = get_match_conds(type_, templ) assert match == {'N1': 2, 'T2': Uint[2]} assert res == type_
def test_tuple_deep(): type_ = Tuple[Tuple[1, 1], Uint[2], Tuple[Tuple[3, 4], Tuple[2, 3]]] templ = Tuple[Tuple['T1', 1], Uint[2], Tuple[Tuple[3, 4], T('TF3', Tuple['T2', 'T3'])]] match, res = get_match_conds(type_, templ) assert match == {'T1': 1, 'T2': 2, 'T3': 3, 'TF3': Tuple[2, 3]} assert res == type_
def test_tuple_deep_related_templates(): type_ = Tuple[Tuple[1, 1], Uint[2], Tuple[Tuple[3, 4], Tuple[1, 2]]] templ = Tuple[Tuple['T1', 1], Uint['T2'], Tuple[Tuple[3, 4], Tuple['T1', 'T2']]] match, res = get_match_conds(type_, templ) assert match == {'T1': 1, 'T2': 2} assert res == type_
def test_maybe(): type_ = Maybe[Uint[8]] templ = Union[Unit, 'data'] match, res = get_match_conds(type_, templ) assert res == type_ assert match == {'data': Uint[8]}
def test_tuple_deep_related_templates_tvar(): type_ = Tuple[Tuple[1, 2], Uint[2], Tuple[Tuple[3, 4], Tuple[1, 2]]] templ = Tuple[T('TF2', Tuple), Uint['T2'], Tuple[Tuple[3, 4], T('TF2', Tuple['T1', 'T2'])]] match, res = get_match_conds(type_, templ) assert match == {'T1': 1, 'T2': 2, 'TF2': Tuple[1, 2]} assert res == type_
def test_namedtuple_tuple(): type_ = Tuple[{'F1': 1, 'F2': 2, 'F3': 3}] templ = Tuple['T1', 'T2', 'T3'] match, res = get_match_conds(type_, templ) assert match == {'T1': 1, 'T2': 2, 'T3': 3} # TODO: These aren't really equal. Think about it # assert res == type_ assert res.fields == ('f0', 'f1', 'f2')
def resolve_arith_func(op, opexp, ctx: Context): if type(op) in resolvers: op_resolvers = resolvers[type(op)] for templ in op_resolvers: try: try: get_match_conds(opexp[0].dtype, templ) except AttributeError: breakpoint() return op_resolvers[templ](opexp, ctx) except TypeMatchError: continue finexpr = ir.BinOpExpr((opexp[0], opexp[1]), type(op)) for opi in opexp[2:]: finexpr = ir.BinOpExpr((finexpr, opi), type(op)) return finexpr
def test_union_template_complex(): type_ = Queue[Union[Uint[3], Uint[3]], 1] templ = Queue[Union['UT1', T('UT2', Uint)], 'lvl'] match, res = get_match_conds(type_, templ) assert res == type_ assert match == {'lvl': 1, 'UT1': Uint[3], 'UT2': Uint[3]}
def test_union_template(): type_ = Union[Uint[3], Uint[3]] templ = Union match, res = get_match_conds(type_, templ) assert res == type_ assert not match
def test_namedtuple_tuple_fail(): type_ = Tuple[{'F1': 1, 'F2': 2, 'F3': 3}] templ = Tuple['T1', 'T2', 'T2'] get_match_conds(type_, templ)
def test_fixp_is_number(): get_match_conds(Fixp[1, 2], Number)
def test_uint(): type_ = Uint[1] templ = Uint['T1'] match, res = get_match_conds(type_, templ) assert match == {'T1': 1} assert res == type_
def test_tuple_single_lvl_related_templates(): type_ = Tuple[1, 2, 3, 2] templ = Tuple[1, 'T1', 3, 'T1'] match, res = get_match_conds(type_, templ) assert match == {'T1': 2} assert res == type_
def test_uint_fail(): type_ = Uint[1] templ = Uint[2] get_match_conds(type_, templ)
def test_tuple_multi_lvl_single_related_template_fail(): type_ = Tuple[1, Uint[2], 3] templ = Tuple[1, T('Ti', Uint['T1']), 'T1'] get_match_conds(type_, templ)
def resolve_gear(gear_inst, out_intfs, out_dtype, fix_intfs): dflt_dout_name = reg['gear/naming/default_out_name'] for i in range(len(gear_inst.outnames), len(out_dtype)): if out_intfs and hasattr(out_intfs[i], 'var_name'): gear_inst.outnames.append(out_intfs[i].var_name) else: gear_inst.outnames.append(dflt_dout_name if len(out_dtype) == 1 else f'{dflt_dout_name}{i}') gear_inst.connect_output(out_intfs, out_dtype) # Connect output interfaces intfs = [] out_intfs = [] if isinstance(fix_intfs, dict): for i, (name, dt) in enumerate(zip(gear_inst.outnames, out_dtype)): if (name in fix_intfs) or (i in fix_intfs): if name in fix_intfs: intf = fix_intfs[name] elif i in fix_intfs: intf = fix_intfs[i] err = None try: get_match_conds(dt, intf.dtype) except (TypeError, TypeMatchError) as e: err = type( e )(f"{str(e)}\n when connecting user supplied output interface '{name}' of '{gear_inst.name}'" f"\n FIX: Consider changing the type of the supplied output interface '{name}' to '{repr(dt)}'" ) if err: raise err else: intf = Intf(dt) out_intfs.append(intf) intfs.append(intf) elif fix_intfs: # TODO: Should we allow partially supplied fix_intfs? Maybe None should # be supplied where a new Intf should be created # TODO: Do similar type checking as above intfs = fix_intfs else: intfs = [Intf(dt) for dt in out_dtype] out_intfs = intfs if len(intfs) != len(gear_inst.out_port_intfs): raise GearArgsNotSpecified( f'Received {len(intfs)} output interfaces,' f' while expecting {len(gear_inst.out_port_intfs)}' f"\n when instantiating '{gear_inst.name}'") for intf, port in zip(intfs, gear_inst.out_ports): intf.source(port) if any(not type_is_specified(i.dtype) for i in out_intfs): raise GearTypeNotSpecified( f'Output type of the gear "{gear_inst.name}"' f' could not be resolved, and resulted in "{repr(out_dtype)}"') for c in gear_inst.child: channel_interfaces(c) if len(out_intfs) > 1: return tuple(out_intfs) elif len(out_intfs) == 1: return out_intfs[0] else: return None
def test_uint_specified(): type_ = Uint[1] templ = Uint[1] match, res = get_match_conds(type_, templ) assert match == {} assert res == type_
def test_uint_omit_var(): type_ = Tuple[Uint[1], Uint[2]] templ = Tuple[Uint, Uint] match, res = get_match_conds(type_, templ) assert match == {} assert res == type_
def test_tuple_single_lvl_partial(): type_ = Tuple[1, 2, 3, 'T2'] templ = Tuple[1, 'T1', 3, 'T2'] match, res = get_match_conds(type_, templ) assert match == {'T1': 2} assert res == type_
def test_tuple_multi_lvl_base_type_conv(): type_ = Tuple[1, Uint[2], 3] templ = Tuple[1, T('T1', Integer['N1']), 3] match, res = get_match_conds(type_, templ) assert match == {'N1': 2, 'T1': Uint[2]} assert res == type_
def test_tuple_single_lvl_related_templates_fail(): type_ = Tuple[1, 2, 3, 2] templ = Tuple[1, 'T1', 'T1', 'T1'] get_match_conds(type_, templ)
def infer_ftypes(params, args, namespace={}): # Add all registered objects (types and transformations) to the namespace namespace = dict(namespace) namespace.update(reg['gear/type_arith']) def is_postponed(name, val): if isinstance(val, bytes): return True if (name in args): return True if (name == 'return'): return not type_is_specified(val) return False postponed = {name: val for name, val in params.items() if is_postponed(name, val)} match = {name: val for name, val in params.items() if name not in postponed} substituted = True final_check = False # Allow for keyword argument values to be templates and provide # a mechanism to resolve these template arguments while substituted or final_check: substituted = False # Loops until none of the parameters has been additionally resolved for name, val in postponed.copy().items(): if name in args: try: templ = val if isinstance(val, bytes): templ = templ.decode() match_update, res = get_match_conds(args[name], templ, match) match.update(match_update) args[name] = res if type_is_specified(res): if is_type(res): res = copy_field_names(res, params[name]) args[name] = res match[name] = res del postponed[name] substituted = True break else: postponed[name] = res except TypeMatchError as e: err = TypeMatchError( f'{str(e)}\n - when deducing type for argument ' f'"{name}"') err.params = match raise err else: try: substituted, new_p = resolve_param(val, match, namespace) if substituted and (name == 'return'): substituted = type_is_specified(new_p) if substituted: if name == 'return': substituted = type_is_specified(new_p) match[name] = new_p del postponed[name] break elif final_check: if new_p is not None: raise TypeMatchError(f'Incomplete type: {repr(new_p)}') else: raise TypeMatchError(f'Incomplete type: {repr(val)}') except Exception as e: if final_check: try: arg_repr = str(e.args[0]) except: arg_repr = repr(e.args[0]) if isinstance(val, bytes): val_repr = val.decode() else: try: val_repr = str(val) except: val_repr = repr(val) if name == 'return': err = type(e)( f'{arg_repr}\n - when resolving ' f'return type "{val_repr}"') else: err = type(e)( f'{arg_repr}\n - when resolving ' f'parameter "{name}": "{val_repr}"') err.params = match raise err final_check = not substituted and not final_check # print('Final postponed: ', postponed) # print('Final match: ', match) for name, val in args.items(): get_match_conds(val, match[name], {}) if postponed: name, value = next(iter(postponed.items())) err = TypeMatchError(f'Parameter "{name}" unresolved: {value}') err.params = match raise err return match
def test_tuple_deep_related_templates_fail(): type_ = Tuple[Tuple[1, 1], Uint[1], Tuple[Tuple[3, 4], Tuple[1, 2]]] templ = Tuple[Tuple['T1', 1], Uint['T2'], Tuple[Tuple[3, 4], T('TF2', Tuple['T1', 'T2'])]] get_match_conds(type_, templ)
def test_tuple_multi_lvl_single_related_template(): type_ = Tuple[1, Uint[2], 2] templ = Tuple[1, Uint['T1'], 'T1'] match, res = get_match_conds(type_, templ) assert match == {'T1': 2} assert res == type_
def test_tuple_namedtuple_fail(): type_ = Tuple[1, 2, 1] templ = Tuple[{'F1': 'T1', 'F2': 'T2', 'F3': 'T2'}] get_match_conds(type_, templ)
def test_conv_from_number(): a = Tuple[Number, Number] b = Tuple[Float, Float] match_update, res = get_match_conds(b, a) assert res[0] is res[1]