phasm/phasm/ourlang.py
Johan B.W. de Vries 234bfaa8df Changes AppliedType to TypeConstructor
First to be more in line with how the literature
treats these types. But also to make them workable with
type classes.
2025-04-21 11:14:30 +02:00

423 lines
11 KiB
Python

"""
Contains the syntax tree for ourlang
"""
import enum
from typing import Dict, Iterable, List, Optional, Union
from typing_extensions import Final
from .type3 import typeclasses as type3typeclasses
from .type3 import types as type3types
from .type3.types import PlaceholderForType, StructType3, Type3, Type3OrPlaceholder
WEBASSEMBLY_BUILTIN_BYTES_OPS: Final = ('len', )
class Expression:
"""
An expression within a statement
"""
__slots__ = ('type3', )
type3: Type3OrPlaceholder
def __init__(self) -> None:
self.type3 = PlaceholderForType([self])
class Constant(Expression):
"""
An constant value expression within a statement
# FIXME: Rename to literal
"""
__slots__ = ()
class ConstantPrimitive(Constant):
"""
An primitive constant value expression within a statement
"""
__slots__ = ('value', )
value: Union[int, float]
def __init__(self, value: Union[int, float]) -> None:
super().__init__()
self.value = value
def __repr__(self) -> str:
return f'ConstantPrimitive({repr(self.value)})'
class ConstantMemoryStored(Constant):
"""
An constant value expression within a statement
# FIXME: Rename to literal
"""
__slots__ = ('data_block', )
data_block: 'ModuleDataBlock'
def __init__(self, data_block: 'ModuleDataBlock') -> None:
super().__init__()
self.data_block = data_block
class ConstantBytes(ConstantMemoryStored):
"""
A bytes constant value expression within a statement
"""
__slots__ = ('value', )
value: bytes
def __init__(self, value: bytes, data_block: 'ModuleDataBlock') -> None:
super().__init__(data_block)
self.value = value
def __repr__(self) -> str:
# Do not repr the whole ModuleDataBlock
# As this has a reference back to this constant for its data
# which it needs to compile the data into the program
return f'ConstantBytes({repr(self.value)}, @{repr(self.data_block.address)})'
class ConstantTuple(ConstantMemoryStored):
"""
A Tuple constant value expression within a statement
"""
__slots__ = ('value', )
value: List[Union[ConstantPrimitive, ConstantBytes, 'ConstantTuple', 'ConstantStruct']]
def __init__(self, value: List[Union[ConstantPrimitive, ConstantBytes, 'ConstantTuple', 'ConstantStruct']], data_block: 'ModuleDataBlock') -> None:
super().__init__(data_block)
self.value = value
def __repr__(self) -> str:
# Do not repr the whole ModuleDataBlock
# As this has a reference back to this constant for its data
# which it needs to compile the data into the program
return f'ConstantTuple({repr(self.value)}, @{repr(self.data_block.address)})'
class ConstantStruct(ConstantMemoryStored):
"""
A Struct constant value expression within a statement
"""
__slots__ = ('struct_name', 'value', )
struct_name: str
value: List[Union[ConstantPrimitive, ConstantBytes, ConstantTuple, 'ConstantStruct']]
def __init__(self, struct_name: str, value: List[Union[ConstantPrimitive, ConstantBytes, ConstantTuple, 'ConstantStruct']], data_block: 'ModuleDataBlock') -> None:
super().__init__(data_block)
self.struct_name = struct_name
self.value = value
def __repr__(self) -> str:
# Do not repr the whole ModuleDataBlock
# As this has a reference back to this constant for its data
# which it needs to compile the data into the program
return f'ConstantStruct({repr(self.struct_name)}, {repr(self.value)}, @{repr(self.data_block.address)})'
class VariableReference(Expression):
"""
An variable reference expression within a statement
"""
__slots__ = ('variable', )
variable: Union['ModuleConstantDef', 'FunctionParam'] # also possibly local
def __init__(self, variable: Union['ModuleConstantDef', 'FunctionParam']) -> None:
super().__init__()
self.variable = variable
class UnaryOp(Expression):
"""
A unary operator expression within a statement
"""
__slots__ = ('operator', 'right', )
operator: str
right: Expression
def __init__(self, operator: str, right: Expression) -> None:
super().__init__()
self.operator = operator
self.right = right
class BinaryOp(Expression):
"""
A binary operator expression within a statement
"""
__slots__ = ('operator', 'left', 'right', )
operator: type3typeclasses.Type3ClassMethod
left: Expression
right: Expression
def __init__(self, operator: type3typeclasses.Type3ClassMethod, left: Expression, right: Expression) -> None:
super().__init__()
self.operator = operator
self.left = left
self.right = right
def __repr__(self) -> str:
return f'BinaryOp({repr(self.operator)}, {repr(self.left)}, {repr(self.right)})'
class FunctionCall(Expression):
"""
A function call expression within a statement
"""
__slots__ = ('function', 'arguments', )
function: Union['Function', type3typeclasses.Type3ClassMethod]
arguments: List[Expression]
def __init__(self, function: Union['Function', type3typeclasses.Type3ClassMethod]) -> None:
super().__init__()
self.function = function
self.arguments = []
class TupleInstantiation(Expression):
"""
Instantiation a tuple
"""
__slots__ = ('elements', )
elements: List[Expression]
def __init__(self, elements: List[Expression]) -> None:
super().__init__()
self.elements = elements
class Subscript(Expression):
"""
A subscript, for example to refer to a static array or tuple
by index
"""
__slots__ = ('varref', 'index', )
varref: VariableReference
index: Expression
def __init__(self, varref: VariableReference, index: Expression) -> None:
super().__init__()
self.varref = varref
self.index = index
class AccessStructMember(Expression):
"""
Access a struct member for reading of writing
"""
__slots__ = ('varref', 'struct_type3', 'member', )
varref: VariableReference
struct_type3: StructType3
member: str
def __init__(self, varref: VariableReference, struct_type3: StructType3, member: str) -> None:
super().__init__()
self.varref = varref
self.struct_type3 = struct_type3
self.member = member
class Fold(Expression):
"""
A (left or right) fold
"""
class Direction(enum.Enum):
"""
Which direction to fold in
"""
LEFT = 0
RIGHT = 1
dir: Direction
func: 'Function'
base: Expression
iter: Expression
def __init__(
self,
dir_: Direction,
func: 'Function',
base: Expression,
iter_: Expression,
) -> None:
super().__init__()
self.dir = dir_
self.func = func
self.base = base
self.iter = iter_
class Statement:
"""
A statement within a function
"""
__slots__ = ()
class StatementPass(Statement):
"""
A pass statement
"""
__slots__ = ()
class StatementReturn(Statement):
"""
A return statement within a function
"""
__slots__ = ('value', )
def __init__(self, value: Expression) -> None:
self.value = value
def __repr__(self) -> str:
return f'StatementReturn({repr(self.value)})'
class StatementIf(Statement):
"""
An if statement within a function
"""
__slots__ = ('test', 'statements', 'else_statements', )
test: Expression
statements: List[Statement]
else_statements: List[Statement]
def __init__(self, test: Expression) -> None:
self.test = test
self.statements = []
self.else_statements = []
class FunctionParam:
"""
A parameter for a Function
"""
__slots__ = ('name', 'type3', )
name: str
type3: Type3OrPlaceholder
def __init__(self, name: str, type3: Optional[Type3]) -> None:
self.name = name
self.type3 = PlaceholderForType([self]) if type3 is None else type3
class Function:
"""
A function processes input and produces output
"""
__slots__ = ('name', 'lineno', 'exported', 'imported', 'statements', 'returns_type3', 'posonlyargs', )
name: str
lineno: int
exported: bool
imported: Optional[str]
statements: List[Statement]
returns_type3: Type3
posonlyargs: List[FunctionParam]
def __init__(self, name: str, lineno: int) -> None:
self.name = name
self.lineno = lineno
self.exported = False
self.imported = None
self.statements = []
self.returns_type3 = type3types.none # FIXME: This could be a placeholder
self.posonlyargs = []
class StructDefinition:
"""
The definition for a struct
"""
__slots__ = ('struct_type3', 'lineno', )
struct_type3: StructType3
lineno: int
def __init__(self, struct_type3: StructType3, lineno: int) -> None:
self.struct_type3 = struct_type3
self.lineno = lineno
class StructConstructor(Function):
"""
The constructor method for a struct
A function will generated to instantiate a struct. The arguments
will be the defaults
"""
__slots__ = ('struct_type3', )
struct_type3: StructType3
def __init__(self, struct_type3: StructType3) -> None:
super().__init__(f'@{struct_type3.name}@__init___@', -1)
self.returns_type3 = struct_type3
for mem, typ in struct_type3.members.items():
self.posonlyargs.append(FunctionParam(mem, typ, ))
self.struct_type3 = struct_type3
class ModuleConstantDef:
"""
A constant definition within a module
"""
__slots__ = ('name', 'lineno', 'type3', 'constant', )
name: str
lineno: int
type3: Type3
constant: Constant
def __init__(self, name: str, lineno: int, type3: Type3, constant: Constant) -> None:
self.name = name
self.lineno = lineno
self.type3 = type3
self.constant = constant
class ModuleDataBlock:
"""
A single allocated block for module data
"""
__slots__ = ('data', 'address', )
data: List[Union[ConstantPrimitive, ConstantMemoryStored]]
address: Optional[int]
def __init__(self, data: Iterable[Union[ConstantPrimitive, ConstantMemoryStored]]) -> None:
self.data = [*data]
self.address = None
class ModuleData:
"""
The data for when a module is loaded into memory
"""
__slots__ = ('blocks', )
blocks: List[ModuleDataBlock]
def __init__(self) -> None:
self.blocks = []
class Module:
"""
A module is a file and consists of functions
"""
__slots__ = ('data', 'types', 'struct_definitions', 'constant_defs', 'functions',)
data: ModuleData
struct_definitions: Dict[str, StructDefinition]
constant_defs: Dict[str, ModuleConstantDef]
functions: Dict[str, Function]
def __init__(self) -> None:
self.data = ModuleData()
self.struct_definitions = {}
self.constant_defs = {}
self.functions = {}