""" The prelude are all the builtin types, type classes and methods """ from typing import Any, Callable from warnings import warn from phasm.stdlib import types as stdtypes from phasm.wasmgenerator import Generator from ..type3.functions import ( Constraint_TypeClassInstanceExists, TypeConstructorVariable, TypeVariable, TypeVariableApplication_Nullary, ) from ..type3.routers import TypeClassArgsRouter, TypeVariableLookup from ..type3.typeclasses import Type3Class, Type3ClassMethod from ..type3.types import ( Type3, TypeApplication_Nullary, TypeConstructor_Base, TypeConstructor_DynamicArray, TypeConstructor_Function, TypeConstructor_StaticArray, TypeConstructor_Struct, TypeConstructor_Tuple, ) PRELUDE_TYPE_CLASS_INSTANCES_EXISTING: set[tuple[Type3Class, tuple[Type3 | TypeConstructor_Base[Any], ...]]] = set() PRELUDE_TYPE_CLASS_INSTANCE_METHODS: dict[Type3ClassMethod, TypeClassArgsRouter[Generator, None]] = {} class MissingImplementationException(Exception): pass class MissingImplementationWarning(Warning): pass def instance_type_class( cls: Type3Class, *typ: Type3 | TypeConstructor_Base[Any], methods: dict[str, Callable[[Generator, TypeVariableLookup], None]] = {}, operators: dict[str, Callable[[Generator, TypeVariableLookup], None]] = {}, ) -> None: global PRELUDE_TYPE_CLASS_INSTANCES_EXISTING global PRELUDE_TYPE_CLASS_INSTANCE_METHODS assert len(cls.args) == len(typ) tv_map: dict[TypeVariable, Type3] = {} tc_map: dict[TypeConstructorVariable, TypeConstructor_Base[Any]] = {} for arg_tv, arg_tp in zip(cls.args, typ, strict=True): if isinstance(arg_tv, TypeVariable): assert isinstance(arg_tp, Type3) tv_map[arg_tv] = arg_tp elif isinstance(arg_tv, TypeConstructorVariable): assert isinstance(arg_tp, TypeConstructor_Base) tc_map[arg_tv] = arg_tp else: raise NotImplementedError(arg_tv, arg_tp) # TODO: Check for required existing instantiations PRELUDE_TYPE_CLASS_INSTANCES_EXISTING.add((cls, tuple(typ), )) for method_name, method in cls.methods.items(): router = PRELUDE_TYPE_CLASS_INSTANCE_METHODS.get(method) if router is None: router = TypeClassArgsRouter[Generator, None](cls.args) PRELUDE_TYPE_CLASS_INSTANCE_METHODS[method] = router try: generator = methods[method_name] except KeyError: warn(MissingImplementationWarning(str(method), cls.name + ' ' + ' '.join(x.name for x in typ))) continue router.add(tv_map, tc_map, generator) for operator_name, operator in cls.operators.items(): router = PRELUDE_TYPE_CLASS_INSTANCE_METHODS.get(operator) if router is None: router = TypeClassArgsRouter[Generator, None](cls.args) PRELUDE_TYPE_CLASS_INSTANCE_METHODS[operator] = router try: generator = operators[operator_name] except KeyError: warn(MissingImplementationWarning(str(operator), cls.name + ' ' + ' '.join(x.name for x in typ))) continue router.add(tv_map, tc_map, generator) none = Type3('none', TypeApplication_Nullary(None, None)) """ The none type, for when functions simply don't return anything. e.g., IO(). """ bool_ = Type3('bool', TypeApplication_Nullary(None, None)) """ The bool type, either True or False Suffixes with an underscores, as it's a Python builtin """ u8 = Type3('u8', TypeApplication_Nullary(None, None)) """ The unsigned 8-bit integer type. Operations on variables employ modular arithmetic, with modulus 2^8. """ u32 = Type3('u32', TypeApplication_Nullary(None, None)) """ The unsigned 32-bit integer type. Operations on variables employ modular arithmetic, with modulus 2^32. """ u64 = Type3('u64', TypeApplication_Nullary(None, None)) """ The unsigned 64-bit integer type. Operations on variables employ modular arithmetic, with modulus 2^64. """ i8 = Type3('i8', TypeApplication_Nullary(None, None)) """ The signed 8-bit integer type. Operations on variables employ modular arithmetic, with modulus 2^8, but with the middel point being 0. """ i32 = Type3('i32', TypeApplication_Nullary(None, None)) """ The unsigned 32-bit integer type. Operations on variables employ modular arithmetic, with modulus 2^32, but with the middel point being 0. """ i64 = Type3('i64', TypeApplication_Nullary(None, None)) """ The unsigned 64-bit integer type. Operations on variables employ modular arithmetic, with modulus 2^64, but with the middel point being 0. """ f32 = Type3('f32', TypeApplication_Nullary(None, None)) """ A 32-bits IEEE 754 float, of 32 bits width. """ f64 = Type3('f64', TypeApplication_Nullary(None, None)) """ A 32-bits IEEE 754 float, of 64 bits width. """ dynamic_array = TypeConstructor_DynamicArray('dynamic_array') """ This is a dynamic length piece of memory. It should be applied with two arguments. It has a runtime determined length, and each argument is the same. """ static_array = TypeConstructor_StaticArray('static_array') """ This is a fixed length piece of memory. It should be applied with two arguments. It has a compile time determined length, and each argument is the same. """ tuple_ = TypeConstructor_Tuple('tuple') """ This is a fixed length piece of memory. It should be applied with zero or more arguments. It has a compile time determined length, and each argument can be different. """ function = TypeConstructor_Function('function') """ This is a function. It should be applied with one or more arguments. The last argument is the 'return' type. """ struct = TypeConstructor_Struct('struct') """ This is like a tuple, but each argument is named, so that developers can get and set fields by name. """ a = TypeVariable('a', TypeVariableApplication_Nullary(None, None)) b = TypeVariable('b', TypeVariableApplication_Nullary(None, None)) t = TypeConstructorVariable('t') Eq = Type3Class('Eq', (a, ), methods={}, operators={ '==': [a, a, bool_], '!=': [a, a, bool_], # FIXME: Do we want to expose 'eqz'? Or is that a compiler optimization? }) instance_type_class(Eq, u8, operators={ '==': stdtypes.u8_eq_equals, '!=': stdtypes.u8_eq_not_equals, }) instance_type_class(Eq, u32, operators={ '==': stdtypes.u32_eq_equals, '!=': stdtypes.u32_eq_not_equals, }) instance_type_class(Eq, u64, operators={ '==': stdtypes.u64_eq_equals, '!=': stdtypes.u64_eq_not_equals, }) instance_type_class(Eq, i8, operators={ '==': stdtypes.i8_eq_equals, '!=': stdtypes.i8_eq_not_equals, }) instance_type_class(Eq, i32, operators={ '==': stdtypes.i32_eq_equals, '!=': stdtypes.i32_eq_not_equals, }) instance_type_class(Eq, i64, operators={ '==': stdtypes.i64_eq_equals, '!=': stdtypes.i64_eq_not_equals, }) instance_type_class(Eq, f32, operators={ '==': stdtypes.f32_eq_equals, '!=': stdtypes.f32_eq_not_equals, }) instance_type_class(Eq, f64, operators={ '==': stdtypes.f64_eq_equals, '!=': stdtypes.f64_eq_not_equals, }) Ord = Type3Class('Ord', (a, ), methods={ 'min': [a, a, a], 'max': [a, a, a], }, operators={ '<': [a, a, bool_], '<=': [a, a, bool_], '>': [a, a, bool_], '>=': [a, a, bool_], }, inherited_classes=[Eq]) instance_type_class(Ord, u8, methods={ 'min': stdtypes.u8_ord_min, 'max': stdtypes.u8_ord_max, }, operators={ '<': stdtypes.u8_ord_less_than, '<=': stdtypes.u8_ord_less_than_or_equal, '>': stdtypes.u8_ord_greater_than, '>=': stdtypes.u8_ord_greater_than_or_equal, }) instance_type_class(Ord, u32, methods={ 'min': stdtypes.u32_ord_min, 'max': stdtypes.u32_ord_max, }, operators={ '<': stdtypes.u32_ord_less_than, '<=': stdtypes.u32_ord_less_than_or_equal, '>': stdtypes.u32_ord_greater_than, '>=': stdtypes.u32_ord_greater_than_or_equal, }) instance_type_class(Ord, u64, methods={ 'min': stdtypes.u64_ord_min, 'max': stdtypes.u64_ord_max, }, operators={ '<': stdtypes.u64_ord_less_than, '<=': stdtypes.u64_ord_less_than_or_equal, '>': stdtypes.u64_ord_greater_than, '>=': stdtypes.u64_ord_greater_than_or_equal, }) instance_type_class(Ord, i8, methods={ 'min': stdtypes.i8_ord_min, 'max': stdtypes.i8_ord_max, }, operators={ '<': stdtypes.i8_ord_less_than, '<=': stdtypes.i8_ord_less_than_or_equal, '>': stdtypes.i8_ord_greater_than, '>=': stdtypes.i8_ord_greater_than_or_equal, }) instance_type_class(Ord, i32, methods={ 'min': stdtypes.i32_ord_min, 'max': stdtypes.i32_ord_max, }, operators={ '<': stdtypes.i32_ord_less_than, '<=': stdtypes.i32_ord_less_than_or_equal, '>': stdtypes.i32_ord_greater_than, '>=': stdtypes.i32_ord_greater_than_or_equal, }) instance_type_class(Ord, i64, methods={ 'min': stdtypes.i64_ord_min, 'max': stdtypes.i64_ord_max, }, operators={ '<': stdtypes.i64_ord_less_than, '<=': stdtypes.i64_ord_less_than_or_equal, '>': stdtypes.i64_ord_greater_than, '>=': stdtypes.i64_ord_greater_than_or_equal, }) instance_type_class(Ord, f32, methods={ 'min': stdtypes.f32_ord_min, 'max': stdtypes.f32_ord_max, }, operators={ '<': stdtypes.f32_ord_less_than, '<=': stdtypes.f32_ord_less_than_or_equal, '>': stdtypes.f32_ord_greater_than, '>=': stdtypes.f32_ord_greater_than_or_equal, }) instance_type_class(Ord, f64, methods={ 'min': stdtypes.f64_ord_min, 'max': stdtypes.f64_ord_max, }, operators={ '<': stdtypes.f64_ord_less_than, '<=': stdtypes.f64_ord_less_than_or_equal, '>': stdtypes.f64_ord_greater_than, '>=': stdtypes.f64_ord_greater_than_or_equal, }) Bits = Type3Class('Bits', (a, ), methods={ 'shl': [a, u32, a], # Logical shift left 'shr': [a, u32, a], # Logical shift right 'rotl': [a, u32, a], # Rotate bits left 'rotr': [a, u32, a], # Rotate bits right # FIXME: Do we want to expose clz, ctz, popcnt? }, operators={ '&': [a, a, a], # Bit-wise and '|': [a, a, a], # Bit-wise or '^': [a, a, a], # Bit-wise xor }) instance_type_class(Bits, u8, methods={ 'shl': stdtypes.u8_bits_logical_shift_left, 'shr': stdtypes.u8_bits_logical_shift_right, 'rotl': stdtypes.u8_bits_rotate_left, 'rotr': stdtypes.u8_bits_rotate_right, }, operators={ '&': stdtypes.u8_bits_bitwise_and, '|': stdtypes.u8_bits_bitwise_or, '^': stdtypes.u8_bits_bitwise_xor, }) instance_type_class(Bits, u32, methods={ 'shl': stdtypes.u32_bits_logical_shift_left, 'shr': stdtypes.u32_bits_logical_shift_right, 'rotl': stdtypes.u32_bits_rotate_left, 'rotr': stdtypes.u32_bits_rotate_right, }, operators={ '&': stdtypes.u32_bits_bitwise_and, '|': stdtypes.u32_bits_bitwise_or, '^': stdtypes.u32_bits_bitwise_xor, }) instance_type_class(Bits, u64, methods={ 'shl': stdtypes.u64_bits_logical_shift_left, 'shr': stdtypes.u64_bits_logical_shift_right, 'rotl': stdtypes.u64_bits_rotate_left, 'rotr': stdtypes.u64_bits_rotate_right, }, operators={ '&': stdtypes.u64_bits_bitwise_and, '|': stdtypes.u64_bits_bitwise_or, '^': stdtypes.u64_bits_bitwise_xor, }) NatNum = Type3Class('NatNum', (a, ), methods={}, operators={ '+': [a, a, a], '-': [a, a, a], '*': [a, a, a], '<<': [a, u32, a], # Arithmic shift left '>>': [a, u32, a], # Arithmic shift right }) instance_type_class(NatNum, u32, operators={ '+': stdtypes.u32_natnum_add, '-': stdtypes.u32_natnum_sub, '*': stdtypes.u32_natnum_mul, '<<': stdtypes.u32_natnum_arithmic_shift_left, '>>': stdtypes.u32_natnum_arithmic_shift_right, }) instance_type_class(NatNum, u64, operators={ '+': stdtypes.u64_natnum_add, '-': stdtypes.u64_natnum_sub, '*': stdtypes.u64_natnum_mul, '<<': stdtypes.u64_natnum_arithmic_shift_left, '>>': stdtypes.u64_natnum_arithmic_shift_right, }) instance_type_class(NatNum, i32, operators={ '+': stdtypes.i32_natnum_add, '-': stdtypes.i32_natnum_sub, '*': stdtypes.i32_natnum_mul, '<<': stdtypes.i32_natnum_arithmic_shift_left, '>>': stdtypes.i32_natnum_arithmic_shift_right, }) instance_type_class(NatNum, i64, operators={ '+': stdtypes.i64_natnum_add, '-': stdtypes.i64_natnum_sub, '*': stdtypes.i64_natnum_mul, '<<': stdtypes.i64_natnum_arithmic_shift_left, '>>': stdtypes.i64_natnum_arithmic_shift_right, }) instance_type_class(NatNum, f32, operators={ '+': stdtypes.f32_natnum_add, '-': stdtypes.f32_natnum_sub, '*': stdtypes.f32_natnum_mul, '<<': stdtypes.f32_natnum_arithmic_shift_left, '>>': stdtypes.f32_natnum_arithmic_shift_right, }) instance_type_class(NatNum, f64, operators={ '+': stdtypes.f64_natnum_add, '-': stdtypes.f64_natnum_sub, '*': stdtypes.f64_natnum_mul, '<<': stdtypes.f64_natnum_arithmic_shift_left, '>>': stdtypes.f64_natnum_arithmic_shift_right, }) IntNum = Type3Class('IntNum', (a, ), methods={ 'abs': [a, a], 'neg': [a, a], }, operators={}, inherited_classes=[NatNum]) instance_type_class(IntNum, i32, methods={ 'abs': stdtypes.i32_intnum_abs, 'neg': stdtypes.i32_intnum_neg, }) instance_type_class(IntNum, i64, methods={ 'abs': stdtypes.i64_intnum_abs, 'neg': stdtypes.i64_intnum_neg, }) instance_type_class(IntNum, f32, methods={ 'abs': stdtypes.f32_intnum_abs, 'neg': stdtypes.f32_intnum_neg, }) instance_type_class(IntNum, f64, methods={ 'abs': stdtypes.f64_intnum_abs, 'neg': stdtypes.f64_intnum_neg, }) Integral = Type3Class('Integral', (a, ), methods={ }, operators={ '//': [a, a, a], '%': [a, a, a], }, inherited_classes=[NatNum]) instance_type_class(Integral, u32, operators={ '//': stdtypes.u32_integral_div, '%': stdtypes.u32_integral_rem, }) instance_type_class(Integral, u64, operators={ '//': stdtypes.u64_integral_div, '%': stdtypes.u64_integral_rem, }) instance_type_class(Integral, i32, operators={ '//': stdtypes.i32_integral_div, '%': stdtypes.i32_integral_rem, }) instance_type_class(Integral, i64, operators={ '//': stdtypes.i64_integral_div, '%': stdtypes.i64_integral_rem, }) Fractional = Type3Class('Fractional', (a, ), methods={ 'ceil': [a, a], 'floor': [a, a], 'trunc': [a, a], 'nearest': [a, a], }, operators={ '/': [a, a, a], }, inherited_classes=[NatNum]) instance_type_class(Fractional, f32, methods={ 'ceil': stdtypes.f32_fractional_ceil, 'floor': stdtypes.f32_fractional_floor, 'trunc': stdtypes.f32_fractional_trunc, 'nearest': stdtypes.f32_fractional_nearest, }, operators={ '/': stdtypes.f32_fractional_div, }) instance_type_class(Fractional, f64, methods={ 'ceil': stdtypes.f64_fractional_ceil, 'floor': stdtypes.f64_fractional_floor, 'trunc': stdtypes.f64_fractional_trunc, 'nearest': stdtypes.f64_fractional_nearest, }, operators={ '/': stdtypes.f64_fractional_div, }) Floating = Type3Class('Floating', (a, ), methods={ 'sqrt': [a, a], }, operators={}, inherited_classes=[Fractional]) # FIXME: Do we want to expose copysign? instance_type_class(Floating, f32, methods={ 'sqrt': stdtypes.f32_floating_sqrt, }) instance_type_class(Floating, f64, methods={ 'sqrt': stdtypes.f64_floating_sqrt, }) Sized_ = Type3Class('Sized', (t, ), methods={ 'len': [t(a), u32], }, operators={}) # FIXME: Once we get type class families, add [] here instance_type_class(Sized_, dynamic_array, methods={ 'len': stdtypes.dynamic_array_sized_len, }) instance_type_class(Sized_, static_array, methods={ 'len': stdtypes.static_array_sized_len, }) Extendable = Type3Class('Extendable', (a, b, ), methods={ 'extend': [a, b], 'wrap': [b, a], }, operators={}) instance_type_class(Extendable, u8, u32, methods={ 'extend': stdtypes.u8_u32_extend, 'wrap': stdtypes.u8_u32_wrap, }) instance_type_class(Extendable, u8, u64, methods={ 'extend': stdtypes.u8_u64_extend, 'wrap': stdtypes.u8_u64_wrap, }) instance_type_class(Extendable, u32, u64, methods={ 'extend': stdtypes.u32_u64_extend, 'wrap': stdtypes.u32_u64_wrap, }) instance_type_class(Extendable, i8, i32, methods={ 'extend': stdtypes.i8_i32_extend, 'wrap': stdtypes.i8_i32_wrap, }) instance_type_class(Extendable, i8, i64, methods={ 'extend': stdtypes.i8_i64_extend, 'wrap': stdtypes.i8_i64_wrap, }) instance_type_class(Extendable, i32, i64, methods={ 'extend': stdtypes.i32_i64_extend, 'wrap': stdtypes.i32_i64_wrap, }) Promotable = Type3Class('Promotable', (a, b, ), methods={ 'promote': [a, b], 'demote': [b, a], }, operators={}) instance_type_class(Promotable, f32, f64, methods={ 'promote': stdtypes.f32_f64_promote, 'demote': stdtypes.f32_f64_demote, }) Reinterpretable = Type3Class('Reinterpretable', (a, b, ), methods={ 'reinterpret': [a, b] }, operators={}) instance_type_class(Reinterpretable, u32, f32, methods={ 'reinterpret': stdtypes.u32_f32_reinterpret, }) instance_type_class(Reinterpretable, u64, f64, methods={ 'reinterpret': stdtypes.u64_f64_reinterpret, }) instance_type_class(Reinterpretable, i32, f32, methods={ 'reinterpret': stdtypes.i32_f32_reinterpret, }) instance_type_class(Reinterpretable, i64, f64, methods={ 'reinterpret': stdtypes.i64_f64_reinterpret, }) instance_type_class(Reinterpretable, f32, u32, methods={ 'reinterpret': stdtypes.f32_u32_reinterpret, }) instance_type_class(Reinterpretable, f64, u64, methods={ 'reinterpret': stdtypes.f64_u64_reinterpret, }) instance_type_class(Reinterpretable, f32, i32, methods={ 'reinterpret': stdtypes.f32_i32_reinterpret, }) instance_type_class(Reinterpretable, f64, i64, methods={ 'reinterpret': stdtypes.f64_i64_reinterpret, }) Convertable = Type3Class('Convertable', (a, b, ), methods={ 'convert': [a, b], 'truncate': [b, a], # To prevent name clas with Fractional }, operators={}) instance_type_class(Convertable, u32, f32, methods={ 'convert': stdtypes.u32_f32_convert, 'truncate': stdtypes.u32_f32_truncate, }) instance_type_class(Convertable, u32, f64, methods={ 'convert': stdtypes.u32_f64_convert, 'truncate': stdtypes.u32_f64_truncate, }) instance_type_class(Convertable, u64, f32, methods={ 'convert': stdtypes.u64_f32_convert, 'truncate': stdtypes.u64_f32_truncate, }) instance_type_class(Convertable, u64, f64, methods={ 'convert': stdtypes.u64_f64_convert, 'truncate': stdtypes.u64_f64_truncate, }) instance_type_class(Convertable, i32, f32, methods={ 'convert': stdtypes.i32_f32_convert, 'truncate': stdtypes.i32_f32_truncate, }) instance_type_class(Convertable, i32, f64, methods={ 'convert': stdtypes.i32_f64_convert, 'truncate': stdtypes.i32_f64_truncate, }) instance_type_class(Convertable, i64, f32, methods={ 'convert': stdtypes.i64_f32_convert, 'truncate': stdtypes.i64_f32_truncate, }) instance_type_class(Convertable, i64, f64, methods={ 'convert': stdtypes.i64_f64_convert, 'truncate': stdtypes.i64_f64_truncate, }) Foldable = Type3Class('Foldable', (t, ), methods={ 'sum': [t(a), a], 'foldl': [[b, a, b], b, t(a), b], 'foldr': [[a, b, b], b, t(a), b], }, operators={}, additional_context={ 'sum': [Constraint_TypeClassInstanceExists(NatNum, (a, ))], }) instance_type_class(Foldable, dynamic_array, methods={ 'sum': stdtypes.dynamic_array_sum, 'foldl': stdtypes.dynamic_array_foldl, 'foldr': stdtypes.dynamic_array_foldr, }) instance_type_class(Foldable, static_array, methods={ 'sum': stdtypes.static_array_sum, 'foldl': stdtypes.static_array_foldl, 'foldr': stdtypes.static_array_foldr, }) bytes_ = dynamic_array(u8) PRELUDE_TYPES: dict[str, Type3] = { 'none': none, 'bool': bool_, 'u8': u8, 'u32': u32, 'u64': u64, 'i8': i8, 'i32': i32, 'i64': i64, 'f32': f32, 'f64': f64, 'bytes': bytes_, } PRELUDE_TYPE_CLASSES = { 'Eq': Eq, 'Ord': Ord, 'Bits': Bits, 'NatNum': NatNum, 'IntNum': IntNum, 'Integral': Integral, 'Fractional': Fractional, 'Floating': Floating, 'Extendable': Extendable, 'Promotable': Promotable, } PRELUDE_OPERATORS = { **Bits.operators, **Eq.operators, **Ord.operators, **Fractional.operators, **Integral.operators, **IntNum.operators, **NatNum.operators, } PRELUDE_METHODS = { **Bits.methods, **Eq.methods, **Ord.methods, **Floating.methods, **Fractional.methods, **Integral.methods, **IntNum.methods, **NatNum.methods, **Sized_.methods, **Extendable.methods, **Promotable.methods, **Reinterpretable.methods, **Convertable.methods, **Foldable.methods, }