phasm/phasm/prelude/__init__.py
2025-05-02 21:05:07 +02:00

325 lines
7.7 KiB
Python

"""
The prelude are all the builtin types, type classes and methods
"""
from ..type3.functions import TypeVariable
from ..type3.typeclasses import Type3Class
from ..type3.types import (
Type3,
TypeConstructor_StaticArray,
TypeConstructor_Struct,
TypeConstructor_Tuple,
)
PRELUDE_TYPE_CLASS_INSTANCES_EXISTING: set[tuple[Type3Class, tuple[Type3, ...]]] = set()
def instance_type_class(cls: Type3Class, *typ: Type3) -> None:
global PRELUDE_TYPE_CLASS_INSTANCES_EXISTING
# TODO: Check for required existing instantiations
PRELUDE_TYPE_CLASS_INSTANCES_EXISTING.add((cls, tuple(typ), ))
none = Type3('none')
"""
The none type, for when functions simply don't return anything. e.g., IO().
"""
bool_ = Type3('bool')
"""
The bool type, either True or False
Suffixes with an underscores, as it's a Python builtin
"""
u8 = Type3('u8')
"""
The unsigned 8-bit integer type.
Operations on variables employ modular arithmetic, with modulus 2^8.
"""
u32 = Type3('u32')
"""
The unsigned 32-bit integer type.
Operations on variables employ modular arithmetic, with modulus 2^32.
"""
u64 = Type3('u64')
"""
The unsigned 64-bit integer type.
Operations on variables employ modular arithmetic, with modulus 2^64.
"""
i8 = Type3('i8')
"""
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')
"""
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')
"""
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')
"""
A 32-bits IEEE 754 float, of 32 bits width.
"""
f64 = Type3('f64')
"""
A 32-bits IEEE 754 float, of 64 bits width.
"""
bytes_ = Type3('bytes')
"""
This is a runtime-determined length piece of memory that can be indexed at runtime.
"""
def sa_on_create(typ: Type3) -> None:
instance_type_class(InternalPassAsPointer, typ)
static_array = TypeConstructor_StaticArray('static_array', on_create=sa_on_create)
"""
A type constructor.
Any static array is a fixed length piece of memory that can be indexed at runtime.
It should be applied with one argument. It has a runtime-dynamic length
of the same type repeated.
"""
def tp_on_create(typ: Type3) -> None:
instance_type_class(InternalPassAsPointer, typ)
tuple_ = TypeConstructor_Tuple('tuple', on_create=tp_on_create)
"""
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.
"""
def st_on_create(typ: Type3) -> None:
instance_type_class(InternalPassAsPointer, typ)
struct = TypeConstructor_Struct('struct', on_create=st_on_create)
"""
This is like a tuple, but each argument is named, so that developers
can get and set fields by name.
"""
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_,
}
a = TypeVariable('a')
b = TypeVariable('b')
InternalPassAsPointer = Type3Class('InternalPassAsPointer', [a], methods={}, operators={})
"""
Internal type class to keep track which types we pass arounds as a pointer.
"""
instance_type_class(InternalPassAsPointer, bytes_)
# instance_type_class(InternalPassAsPointer, static_array)
# instance_type_class(InternalPassAsPointer, tuple_)
# instance_type_class(InternalPassAsPointer, struct)
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)
instance_type_class(Eq, u32)
instance_type_class(Eq, u64)
instance_type_class(Eq, i8)
instance_type_class(Eq, i32)
instance_type_class(Eq, i64)
instance_type_class(Eq, f32)
instance_type_class(Eq, f64)
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)
instance_type_class(Ord, u32)
instance_type_class(Ord, u64)
instance_type_class(Ord, i8)
instance_type_class(Ord, i32)
instance_type_class(Ord, i64)
instance_type_class(Ord, f32)
instance_type_class(Ord, f64)
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)
instance_type_class(Bits, u32)
instance_type_class(Bits, u64)
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)
instance_type_class(NatNum, u64)
instance_type_class(NatNum, i32)
instance_type_class(NatNum, i64)
instance_type_class(NatNum, f32)
instance_type_class(NatNum, f64)
IntNum = Type3Class('IntNum', [a], methods={
'abs': [a, a],
'neg': [a, a],
}, operators={}, inherited_classes=[NatNum])
instance_type_class(IntNum, i32)
instance_type_class(IntNum, i64)
instance_type_class(IntNum, f32)
instance_type_class(IntNum, f64)
Integral = Type3Class('Eq', [a], methods={
}, operators={
'//': [a, a, a],
'%': [a, a, a],
}, inherited_classes=[NatNum])
instance_type_class(Integral, u32)
instance_type_class(Integral, u64)
instance_type_class(Integral, i32)
instance_type_class(Integral, i64)
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)
instance_type_class(Fractional, f64)
Floating = Type3Class('Floating', [a], methods={
'sqrt': [a, a],
}, operators={}, inherited_classes=[Fractional])
# FIXME: Do we want to expose copysign?
instance_type_class(Floating, f32)
instance_type_class(Floating, f64)
Sized_ = Type3Class('Sized', [a], methods={
'len': [a, u32],
}, operators={}) # FIXME: Once we get type class families, add [] here
instance_type_class(Sized_, bytes_)
Extendable = Type3Class('Extendable', [a, b], methods={
'extend': [a, b],
'wrap': [b, a],
}, operators={})
instance_type_class(Extendable, u8, u32)
instance_type_class(Extendable, u8, u64)
instance_type_class(Extendable, u32, u64)
instance_type_class(Extendable, i8, i32)
instance_type_class(Extendable, i8, i64)
instance_type_class(Extendable, i32, i64)
Promotable = Type3Class('Promotable', [a, b], methods={
'promote': [a, b],
'demote': [b, a],
}, operators={})
instance_type_class(Promotable, f32, f64)
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,
}