def _make_bitcast_symbol(symbol_table: SymbolTable, context: CodegenContext) -> OverloadSet: del symbol_table # only to keep API consistent del context to_type, from_type = PlaceholderTemplateType('T'), PlaceholderTemplateType( 'U') bitcast_signature = BitcastFunctionSignature( placeholder_template_types=[to_type, from_type], return_type=to_type, arg_identifiers=['from'], arg_types=[from_type], arg_type_narrowings=[to_type]) return OverloadSet('bitcast', [bitcast_signature])
def test_narrow_type_templates(): from sleepy.types import narrow_type, UnionType, PlaceholderTemplateType, StructType from sleepy.builtin_symbols import SLEEPY_INT, SLEEPY_BOOL context = make_test_context() Int, Bool = SLEEPY_INT, SLEEPY_BOOL T = PlaceholderTemplateType('T') List = StructType(identity=StructIdentity('List', context=context), template_param_or_arg=[T], member_identifiers=[], member_types=[]) # narrow(0:List[Int]|1:List[Bool], List[Int]) = 0:List[Int] assert_equal( narrow_type( UnionType.from_types( [List.replace_types({T: Int}), List.replace_types({T: Bool})]), List.replace_types({T: Int})), UnionType.from_types([List.replace_types({T: Int})])) # narrow(List[Int|Bool], List[Int]) = List[Int|Bool] assert_equal( narrow_type(List.replace_types({T: UnionType.from_types([Int, Bool])}), List.replace_types({T: Int})), List.replace_types({T: UnionType.from_types([Int, Bool])})) # narrow(List[Int|Bool]|List[Int], List[Int]) = List[Int|Bool]|List[Int] assert_equal( narrow_type( UnionType.from_types([ List.replace_types({T: UnionType.from_types([Int, Bool])}), List.replace_types({T: Int}) ]), List.replace_types({T: Int})), UnionType.from_types([ List.replace_types({T: UnionType.from_types([Int, Bool])}), List.replace_types({T: Int}) ]))
def test_try_infer_templ_types_simple(): from sleepy.types import try_infer_template_arguments, PlaceholderTemplateType from sleepy.builtin_symbols import SLEEPY_INT from sleepy.builtin_symbols import SLEEPY_DOUBLE T = PlaceholderTemplateType('T') U = PlaceholderTemplateType('U') assert_equal( try_infer_template_arguments(calling_types=[], signature_types=[], template_parameters=[]), []) assert_equal( try_infer_template_arguments( calling_types=[SLEEPY_INT, SLEEPY_DOUBLE], signature_types=[SLEEPY_INT, SLEEPY_DOUBLE], template_parameters=[]), []) assert_equal( try_infer_template_arguments( calling_types=[SLEEPY_INT, SLEEPY_DOUBLE], signature_types=[SLEEPY_INT, SLEEPY_DOUBLE], template_parameters=[T]), None) assert_equal( try_infer_template_arguments(calling_types=[SLEEPY_INT], signature_types=[T], template_parameters=[T]), [SLEEPY_INT]) assert_equal( try_infer_template_arguments(calling_types=[SLEEPY_INT, SLEEPY_INT], signature_types=[T, T], template_parameters=[T]), [SLEEPY_INT]) assert_equal( try_infer_template_arguments(calling_types=[SLEEPY_INT, SLEEPY_DOUBLE], signature_types=[T, SLEEPY_DOUBLE], template_parameters=[T]), [SLEEPY_INT]) assert_equal( try_infer_template_arguments(calling_types=[SLEEPY_INT, SLEEPY_DOUBLE], signature_types=[SLEEPY_INT, T], template_parameters=[T]), [SLEEPY_DOUBLE]) assert_equal( try_infer_template_arguments(calling_types=[SLEEPY_INT, SLEEPY_DOUBLE], signature_types=[T, U], template_parameters=[T, U]), [SLEEPY_INT, SLEEPY_DOUBLE]) assert_equal( try_infer_template_arguments(calling_types=[SLEEPY_INT, SLEEPY_DOUBLE], signature_types=[T, U], template_parameters=[U, T]), [SLEEPY_DOUBLE, SLEEPY_INT])
def _make_ref_symbol(symbol_table: SymbolTable, context: CodegenContext) -> TypeTemplateSymbol: del symbol_table # only to keep API consistent del context pointee_type = PlaceholderTemplateType(identifier='T') ref_type = ReferenceType(pointee_type=pointee_type) return TypeTemplateSymbol(template_parameters=[pointee_type], signature_type=ref_type)
def test_try_infer_template_arguments_ptr(): from sleepy.types import try_infer_template_arguments, PlaceholderTemplateType, PointerType from sleepy.builtin_symbols import SLEEPY_CHAR from sleepy.builtin_symbols import SLEEPY_INT T = PlaceholderTemplateType('T') assert_equal( try_infer_template_arguments(calling_types=[PointerType(SLEEPY_INT)], signature_types=[PointerType(T)], template_parameters=[T]), [SLEEPY_INT]) assert_equal( try_infer_template_arguments( calling_types=[PointerType(SLEEPY_CHAR), SLEEPY_INT], signature_types=[PointerType(T), SLEEPY_INT], template_parameters=[T]), [SLEEPY_CHAR])
def _make_raw_ptr_symbol(symbol_table: SymbolTable, context: CodegenContext) -> TypeTemplateSymbol: # add destructor destructor_signature = BuiltinOperationFunctionSignature( identifier='free', placeholder_template_types=[], return_type=SLEEPY_UNIT, arg_identifiers=['raw_ptr'], arg_types=[SLEEPY_RAW_PTR], arg_type_narrowings=[SLEEPY_NEVER], instruction=lambda builder, value: SLEEPY_UNIT.unit_constant()) symbol_table.add_overload('free', destructor_signature) pointee_type = PlaceholderTemplateType(identifier='T') ptr_type = PointerType(pointee_type=pointee_type) # RawPtr[T](Ptr[T]) -> RawPtr from_specific_signature = BitcastFunctionSignature( placeholder_template_types=[pointee_type], return_type=SLEEPY_RAW_PTR, arg_identifiers=['ptr'], arg_types=[ptr_type], arg_type_narrowings=[ptr_type]) symbol_table.add_overload('RawPtr', from_specific_signature) # RawPtr(Int) -> RawPtr from_int_signatures = { BuiltinOperationFunctionSignature( identifier='RawPtr', placeholder_template_types=[], return_type=SLEEPY_RAW_PTR, arg_identifiers=['int'], arg_types=[int_type], arg_type_narrowings=[int_type], instruction=lambda builder, integer: builder.inttoptr( integer, typ=SLEEPY_RAW_PTR.ir_type, name='int_to_ptr')) for int_type in INT_TYPES } symbol_table.add_overload('int_to_ptr', from_int_signatures) SLEEPY_RAW_PTR.constructor = OverloadSet(identifier='RawPtr', signatures=from_int_signatures | {from_specific_signature}) raw_ptr_symbol = TypeTemplateSymbol.make_concrete_type_symbol( SLEEPY_RAW_PTR) return raw_ptr_symbol
def test_struct_self_referencing(): from sleepy.types import StructType, PlaceholderTemplateType, PartialIdentifiedStructType, ReferenceType from sleepy.builtin_symbols import SLEEPY_INT context = make_test_context() struct_identity = StructIdentity("List", context=context) T = PlaceholderTemplateType(identifier="T") ListTPartial = PartialIdentifiedStructType(identity=struct_identity, template_param_or_arg=[T]) ListT = StructType(identity=struct_identity, template_param_or_arg=[T], member_identifiers=["val", "next"], member_types=[T, ReferenceType(ListTPartial)], partial_struct_type=ListTPartial) assert_equal(ListT.member_types, [T, ReferenceType(ListT)]) Int = SLEEPY_INT ListInt = ListT.replace_types({T: Int}) assert isinstance(ListInt, StructType) assert_equal(ListInt.member_types, [Int, ReferenceType(ListInt)])
def test_try_infer_templ_types_struct(): from sleepy.types import try_infer_template_arguments, PlaceholderTemplateType, StructType from sleepy.builtin_symbols import SLEEPY_CHAR, SLEEPY_INT context = make_test_context() T = PlaceholderTemplateType('T') U = PlaceholderTemplateType('U') WrapperT = StructType(StructIdentity('Wrapper', context=context), template_param_or_arg=[T], member_identifiers=['value'], member_types=[T]) WrapperU = WrapperT.replace_types({T: U}) WrapperInt = WrapperT.replace_types({T: SLEEPY_INT}) WrapperChar = WrapperT.replace_types({T: SLEEPY_CHAR}) assert_equal( try_infer_template_arguments(calling_types=[WrapperInt], signature_types=[WrapperT], template_parameters=[T]), [SLEEPY_INT]) assert_equal( try_infer_template_arguments(calling_types=[WrapperInt], signature_types=[T], template_parameters=[T]), [WrapperInt]) assert_equal( try_infer_template_arguments(calling_types=[SLEEPY_INT], signature_types=[WrapperT], template_parameters=[T]), None) assert_equal( try_infer_template_arguments(calling_types=[WrapperInt, WrapperInt], signature_types=[WrapperT, WrapperT], template_parameters=[T]), [SLEEPY_INT]) assert_equal( try_infer_template_arguments(calling_types=[WrapperInt, WrapperChar], signature_types=[WrapperT, WrapperU], template_parameters=[T, U]), [SLEEPY_INT, SLEEPY_CHAR]) assert_equal( try_infer_template_arguments(calling_types=[WrapperInt, SLEEPY_INT], signature_types=[WrapperT, T], template_parameters=[T]), [SLEEPY_INT]) assert_equal( try_infer_template_arguments(calling_types=[WrapperChar, SLEEPY_INT], signature_types=[WrapperT, T], template_parameters=[T]), None) assert_equal( try_infer_template_arguments(calling_types=[SLEEPY_INT, SLEEPY_INT], signature_types=[WrapperT, T], template_parameters=[T]), None) # with templates in calling_types assert_equal( try_infer_template_arguments(calling_types=[T, WrapperT], signature_types=[WrapperT, WrapperT], template_parameters=[T]), None) assert_equal( try_infer_template_arguments(calling_types=[WrapperT, T], signature_types=[WrapperT, WrapperT], template_parameters=[T]), None) assert_equal( try_infer_template_arguments(calling_types=[WrapperT, WrapperT], signature_types=[T, WrapperT], template_parameters=[T]), None) assert_equal( try_infer_template_arguments(calling_types=[WrapperT, WrapperT], signature_types=[WrapperT, T], template_parameters=[T]), None)
def test_can_implicit_cast_to(): from sleepy.types import can_implicit_cast_to, ReferenceType, UnionType, StructType, PlaceholderTemplateType from sleepy.builtin_symbols import SLEEPY_INT, SLEEPY_DOUBLE context = make_test_context() assert_equal(can_implicit_cast_to(SLEEPY_INT, SLEEPY_DOUBLE), False) assert_equal(can_implicit_cast_to(SLEEPY_INT, SLEEPY_INT), True) assert_equal( can_implicit_cast_to(UnionType.from_types([SLEEPY_INT]), SLEEPY_INT), True) assert_equal( can_implicit_cast_to(UnionType.from_types([SLEEPY_INT, SLEEPY_DOUBLE]), SLEEPY_DOUBLE), False) assert_equal( can_implicit_cast_to(SLEEPY_DOUBLE, UnionType.from_types([SLEEPY_INT, SLEEPY_DOUBLE])), True) assert_equal( can_implicit_cast_to(ReferenceType(SLEEPY_INT), ReferenceType(SLEEPY_DOUBLE)), False) assert_equal( can_implicit_cast_to(ReferenceType(SLEEPY_INT), ReferenceType(SLEEPY_INT)), True) assert_equal( can_implicit_cast_to( ReferenceType(UnionType.from_types([SLEEPY_INT, SLEEPY_DOUBLE])), ReferenceType(SLEEPY_INT)), False) assert_equal( can_implicit_cast_to( ReferenceType(SLEEPY_INT), ReferenceType(UnionType.from_types([SLEEPY_INT, SLEEPY_DOUBLE]))), False) T = PlaceholderTemplateType('T') List = StructType(identity=StructIdentity('List', context=context), template_param_or_arg=[T], member_identifiers=[], member_types=[]) assert_equal( can_implicit_cast_to( ReferenceType(SLEEPY_INT), ReferenceType(UnionType.from_types([SLEEPY_INT, SLEEPY_DOUBLE]))), False) assert_equal( can_implicit_cast_to( ReferenceType(UnionType.from_types([SLEEPY_INT, SLEEPY_DOUBLE])), ReferenceType(SLEEPY_INT)), False) assert_equal( can_implicit_cast_to( ReferenceType(UnionType.from_types([SLEEPY_INT, SLEEPY_DOUBLE])), UnionType.from_types( [ReferenceType(SLEEPY_INT), ReferenceType(SLEEPY_DOUBLE)])), False) assert_equal( can_implicit_cast_to( List.replace_types( {T: UnionType.from_types([SLEEPY_INT, SLEEPY_DOUBLE])}), List.replace_types({T: SLEEPY_INT})), False) assert_equal( can_implicit_cast_to( List.replace_types({T: SLEEPY_INT}), List.replace_types( {T: UnionType.from_types([SLEEPY_INT, SLEEPY_DOUBLE])})), False)
def _make_ptr_symbol(symbol_table: SymbolTable, context: CodegenContext) -> TypeTemplateSymbol: pointee_type = PlaceholderTemplateType(identifier='T') ptr_type = PointerType(pointee_type=pointee_type) assert 'load' not in symbol_table load_signature = BuiltinOperationFunctionSignature( identifier='load', placeholder_template_types=[pointee_type], return_type=ReferenceType(pointee_type), arg_identifiers=['ptr'], arg_types=[ptr_type], arg_type_narrowings=[ptr_type], instruction=lambda builder, ptr: ptr) symbol_table.add_overload('load', load_signature) assert 'store' not in symbol_table store_signature = BuiltinOperationFunctionSignature( identifier='store', placeholder_template_types=[pointee_type], return_type=SLEEPY_UNIT, arg_identifiers=['ptr', 'value'], arg_types=[ptr_type, pointee_type], arg_type_narrowings=[ptr_type, pointee_type], instruction=lambda builder, ptr, value: builder.store(value=value, ptr=ptr)) symbol_table.add_overload('store', store_signature) # cast from RawPtr -> Ptr[T] and Ref[T] -> Ptr[T] constructor_signature = BitcastFunctionSignature( placeholder_template_types=[pointee_type], return_type=ptr_type, arg_identifiers=['raw_ptr'], arg_types=[SLEEPY_RAW_PTR], arg_type_narrowings=[ptr_type]) ref_cast_signature = BuiltinOperationFunctionSignature( identifier='Ptr', placeholder_template_types=[pointee_type], return_type=ptr_type, arg_identifiers=['reference'], arg_types=[ReferenceType(pointee_type)], arg_type_narrowings=[ReferenceType(pointee_type)], instruction=lambda builder, ptr: ptr) ptr_type.constructor = OverloadSet( 'Ptr', [constructor_signature, ref_cast_signature]) ptr_op_decls = [ (BuiltinBinaryOps.Addition, [(lambda builder, lhs, rhs: builder.gep(lhs, (rhs, )), [ptr_type, i ], ptr_type) for i in INT_TYPES] + [(lambda builder, lhs, rhs: builder.gep(rhs, (lhs, )), [i, ptr_type ], ptr_type) for i in INT_TYPES]), (BuiltinBinaryOps.Subtraction, [(lambda builder, lhs, rhs: builder.gep( lhs, (builder.mul(ir.Constant(i.ir_type, -1), rhs), )), [ptr_type, i], ptr_type) for i in INT_TYPES]) ] ptr_op_decls += [(op, [ (lambda builder, lhs, rhs, op=op: builder.icmp_unsigned( op.value, lhs, rhs), [ptr_type, ptr_type], SLEEPY_BOOL) ]) for op in Simple_Comparison_Ops] for operator, overloads in ptr_op_decls: for instruction, arg_types, return_type in overloads: signature = _make_func_signature( identifier=operator.value, instruction=instruction, op_placeholder_templ_types=[pointee_type], op_arg_types=arg_types, op_return_type=return_type) symbol_table.add_overload(operator.value, signature) free_signature = BuiltinOperationFunctionSignature( identifier='free', placeholder_template_types=[pointee_type], return_type=SLEEPY_UNIT, arg_identifiers=['ptr'], arg_types=[ptr_type], arg_type_narrowings=[SLEEPY_NEVER], instruction=lambda builder, value: SLEEPY_UNIT.unit_constant()) symbol_table.add_overload('free', free_signature) return TypeTemplateSymbol(template_parameters=[pointee_type], signature_type=ptr_type)