phasm/phasm/build/typerouter.py
Johan B.W. de Vries b511439746 Replaces type3 with type5
type5 is much more first principles based, so we get a lot
of weird quirks removed:

- FromLiteral no longer needs to understand AST
- Type unifications works more like Haskell
- Function types are just ordinary types, saving a lot of
  manual busywork

and more.
2025-08-04 18:51:20 +02:00

151 lines
4.3 KiB
Python

from __future__ import annotations
from typing import TYPE_CHECKING, Any
from ..type5.record import Record
from ..type5.typeexpr import (
AtomicType,
TypeApplication,
TypeConstructor,
TypeExpr,
TypeVariable,
)
from ..type5.typerouter import TypeRouter
if TYPE_CHECKING:
from .base import BuildBase
class BuildTypeRouter[T](TypeRouter[T]):
"""
Extends the general type router with phasm builtin types.
Like functions, tuples, static and dynamic arrays.
"""
__slots__ = ('build', )
def __init__(self, build: BuildBase[Any]) -> None:
self.build = build
def when_application(self, typ: TypeApplication) -> T:
da_arg = self.build.type5_is_dynamic_array(typ)
if da_arg is not None:
return self.when_dynamic_array(da_arg)
fn_args = self.build.type5_is_function(typ)
if fn_args is not None:
return self.when_function(fn_args)
sa_args = self.build.type5_is_static_array(typ)
if sa_args is not None:
sa_len, sa_typ = sa_args
return self.when_static_array(sa_len, sa_typ)
tp_args = self.build.type5_is_tuple(typ)
if tp_args is not None:
return self.when_tuple(tp_args)
return self.when_application_other(typ)
def when_record(self, typ: Record) -> T:
return self.when_struct(typ)
def when_application_other(self, typ: TypeApplication) -> T:
raise NotImplementedError
def when_dynamic_array(self, da_arg: TypeExpr) -> T:
raise NotImplementedError
def when_function(self, fn_args: list[TypeExpr]) -> T:
raise NotImplementedError
def when_struct(self, typ: Record) -> T:
raise NotImplementedError
def when_static_array(self, sa_len: int, sa_typ: TypeExpr) -> T:
raise NotImplementedError
def when_tuple(self, tp_args: list[TypeExpr]) -> T:
raise NotImplementedError
class TypeName(BuildTypeRouter[str]):
"""
Router to generate a type's name.
Also serves an example implementation.
"""
__slots__ = ()
def when_application_other(self, typ: TypeApplication) -> str:
return typ.name
def when_atomic(self, typ: AtomicType) -> str:
return typ.name
def when_constructor(self, typ: TypeConstructor) -> str:
return typ.name
def when_dynamic_array(self, da_arg: TypeExpr) -> str:
if da_arg == self.build.u8_type5:
return 'bytes'
return self(da_arg) + '[...]'
def when_function(self, fn_args: list[TypeExpr]) -> str:
return 'Callable[' + ', '.join(map(self, fn_args)) + ']'
def when_static_array(self, sa_len: int, sa_typ: TypeExpr) -> str:
return f'{self(sa_typ)}[{sa_len}]'
def when_struct(self, typ: Record) -> str:
return typ.name
def when_tuple(self, tp_args: list[TypeExpr]) -> str:
return '(' + ', '.join(map(self, tp_args)) + ', )'
def when_variable(self, typ: TypeVariable) -> str:
return typ.name
class TypeAllocSize(BuildTypeRouter[int]):
"""
Router to generate a type's allocation size.
"""
__slots__ = ('is_member', )
is_member: bool
def __init__(self, build: BuildBase[Any], is_member: bool) -> None:
super().__init__(build)
self.is_member = is_member
def when_atomic(self, typ: AtomicType) -> int:
typ_info = self.build.type_info_map.get(typ.name)
if typ_info is None:
raise NotImplementedError(typ)
return typ_info.alloc_size
def when_dynamic_array(self, da_arg: TypeExpr) -> int:
if self.is_member:
return self.build.type_info_constructed.alloc_size
raise RuntimeError("Cannot know size of dynamic array at type level")
def when_static_array(self, sa_len: int, sa_typ: TypeExpr) -> int:
if self.is_member:
return self.build.type_info_constructed.alloc_size
raise NotImplementedError
def when_struct(self, typ: Record) -> int:
if self.is_member:
return self.build.type_info_constructed.alloc_size
return sum(map(self.build.type5_alloc_size_member, (x[1] for x in typ.fields)))
def when_tuple(self, tp_args: list[TypeExpr]) -> int:
if self.is_member:
return self.build.type_info_constructed.alloc_size
return sum(map(self.build.type5_alloc_size_member, tp_args))