phasm/phasm/prelude/__init__.py
Johan B.W. de Vries c2eaaa7e4a Removes the special casing for foldl
Has to implement both functions as arguments and type
place holders (variables) for type constructors.
2025-04-27 15:34:10 +02:00

292 lines
6.7 KiB
Python

"""
The prelude are all the builtin types, type classes and methods
"""
from ..type3.typeclasses import (
Type3Class,
TypeConstructorVariable,
TypeVariable,
instance_type_class,
)
from ..type3.types import (
Type3,
TypeConstructor_StaticArray,
TypeConstructor_Struct,
TypeConstructor_Tuple,
)
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.
"""
static_array = TypeConstructor_StaticArray('static_array', [], [])
"""
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.
"""
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.
"""
struct = TypeConstructor_Struct('struct', [], [])
"""
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')
t = TypeConstructorVariable('t')
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)
instance_type_class(Eq, static_array)
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_)
Foldable = Type3Class('Foldable', [t], methods={
'foldl': [[a, b, b], b, t(a), b],
}, operators={})
PRELUDE_TYPE_CLASSES = {
'Eq': Eq,
'Ord': Ord,
'Bits': Bits,
'NatNum': NatNum,
'IntNum': IntNum,
'Integral': Integral,
'Fractional': Fractional,
'Floating': Floating,
}
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,
}