phasm/phasm/ourlang.py
Johan B.W. de Vries a110fe8405 Notes
2025-08-02 12:17:55 +02:00

465 lines
14 KiB
Python

"""
Contains the syntax tree for ourlang
"""
from typing import Dict, Iterable, List, Optional, Union
from .build.base import BuildBase
from .type3.functions import FunctionSignature, TypeVariableContext
from .type3.typeclasses import Type3ClassMethod
from .type3.types import Type3, TypeApplication_Struct
from .type5 import record as type5record
from .type5 import typeexpr as type5typeexpr
class SourceRef:
__slots__ = ('filename', 'lineno', 'colno', )
filename: str | None
lineno: int | None
colno: int | None
def __init__(self, filename: str | None, lineno: int | None = None, colno: int | None = None) -> None:
self.filename = filename
self.lineno = lineno
self.colno = colno
def __repr__(self) -> str:
return f"SourceRef({self.filename!r}, {self.lineno!r}, {self.colno!r})"
def __str__(self) -> str:
return f"{self.filename}:{self.lineno:>4}:{self.colno:<3}"
class Expression:
"""
An expression within a statement
"""
__slots__ = ('type3', 'type5', 'sourceref', )
sourceref: SourceRef
type3: Type3 | None
type5: type5typeexpr.TypeExpr | None
def __init__(self, *, sourceref: SourceRef | None = None) -> None:
assert sourceref is not None # TODO: Move to type level
self.sourceref = sourceref
self.type3 = None
self.type5 = None
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], sourceref: SourceRef) -> None:
super().__init__(sourceref=sourceref)
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', sourceref: SourceRef) -> None:
super().__init__(sourceref=sourceref)
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', sourceref: SourceRef) -> None:
super().__init__(data_block, sourceref=sourceref)
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', sourceref: SourceRef) -> None:
super().__init__(data_block, sourceref=sourceref)
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_type3', 'value', )
struct_type3: Type3
value: List[Union[ConstantPrimitive, ConstantBytes, ConstantTuple, 'ConstantStruct']]
def __init__(self, struct_type3: Type3, value: List[Union[ConstantPrimitive, ConstantBytes, ConstantTuple, 'ConstantStruct']], data_block: 'ModuleDataBlock', sourceref: SourceRef) -> None:
super().__init__(data_block, sourceref=sourceref)
self.struct_type3 = struct_type3
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({self.struct_type3!r}, {self.value!r}, @{self.data_block.address!r})'
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'], sourceref: SourceRef) -> None:
super().__init__(sourceref=sourceref)
self.variable = variable
class BinaryOp(Expression):
"""
A binary operator expression within a statement
"""
__slots__ = ('operator', 'left', 'right', )
operator: Type3ClassMethod
left: Expression
right: Expression
def __init__(self, operator: Type3ClassMethod, left: Expression, right: Expression, sourceref: SourceRef) -> None:
super().__init__(sourceref=sourceref)
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', 'FunctionParam', Type3ClassMethod]
arguments: List[Expression]
def __init__(self, function: Union['Function', 'FunctionParam', Type3ClassMethod], sourceref: SourceRef) -> None:
super().__init__(sourceref=sourceref)
self.function = function
self.arguments = []
class FunctionReference(Expression):
"""
An function reference expression within a statement
"""
__slots__ = ('function', )
function: 'Function'
def __init__(self, function: 'Function', sourceref: SourceRef) -> None:
super().__init__(sourceref=sourceref)
self.function = function
class TupleInstantiation(Expression):
"""
Instantiation a tuple
"""
__slots__ = ('elements', )
elements: List[Expression]
def __init__(self, elements: List[Expression], sourceref: SourceRef) -> None:
super().__init__(sourceref=sourceref)
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, sourceref: SourceRef) -> None:
super().__init__(sourceref=sourceref)
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: Type3
member: str
def __init__(self, varref: VariableReference, struct_type3: Type3, member: str, sourceref: SourceRef) -> None:
super().__init__(sourceref=sourceref)
self.varref = varref
self.struct_type3 = struct_type3
self.member = member
class Statement:
"""
A statement within a function
"""
__slots__ = ("sourceref", )
sourceref: SourceRef
def __init__(self, *, sourceref: SourceRef | None = None) -> None:
assert sourceref is not None # TODO: Move to type level
self.sourceref = sourceref
class StatementPass(Statement):
"""
A pass statement
"""
__slots__ = ()
def __init__(self, sourceref: SourceRef) -> None:
super().__init__(sourceref=sourceref)
class StatementReturn(Statement):
"""
A return statement within a function
"""
__slots__ = ('value', )
def __init__(self, value: Expression, sourceref: SourceRef) -> None:
super().__init__(sourceref=sourceref)
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', 'type5', )
name: str
type3: Type3
type5: type5typeexpr.TypeExpr
def __init__(self, name: str, type3: Type3, type5: type5typeexpr.TypeExpr) -> None:
assert type5typeexpr.is_concrete(type5)
self.name = name
self.type3 = type3
self.type5 = type5
def __repr__(self) -> str:
return f'FunctionParam({self.name!r}, {self.type3!r})'
class Function:
"""
A function processes input and produces output
"""
__slots__ = ('name', 'sourceref', 'exported', 'imported', 'statements', 'signature', 'returns_type3', 'type5', 'posonlyargs', )
name: str
sourceref: SourceRef
exported: bool
imported: Optional[str]
statements: List[Statement]
signature: FunctionSignature
returns_type3: Type3
type5: type5typeexpr.TypeExpr | None
posonlyargs: List[FunctionParam]
def __init__(self, name: str, sourceref: SourceRef, returns_type3: Type3) -> None:
self.name = name
self.sourceref = sourceref
self.exported = False
self.imported = None
self.statements = []
self.signature = FunctionSignature(TypeVariableContext(), [])
self.returns_type3 = returns_type3
self.type5 = None
self.posonlyargs = []
class StructDefinition:
"""
The definition for a struct
"""
__slots__ = ('struct_type3', 'struct_type5', 'sourceref', )
struct_type3: Type3
struct_type5: type5record.Record
sourceref: SourceRef
def __init__(self, struct_type3: Type3, struct_type5: type5record.Record, sourceref: SourceRef) -> None:
self.struct_type3 = struct_type3
self.struct_type5 = struct_type5
self.sourceref = sourceref
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_type5', )
struct_type3: Type3
struct_type5: type5record.Record
def __init__(self, struct_type3: Type3, struct_type5: type5record.Record, sourceref: SourceRef) -> None:
super().__init__(f'@{struct_type3.name}@__init___@', sourceref, struct_type3)
assert isinstance(struct_type3.application, TypeApplication_Struct)
mem_typ5_map = dict(struct_type5.fields)
for mem, typ in struct_type3.application.arguments:
self.posonlyargs.append(FunctionParam(mem, typ, mem_typ5_map[mem]))
self.signature.args.append(typ)
self.signature.args.append(struct_type3)
self.struct_type3 = struct_type3
self.struct_type5 = struct_type5
class ModuleConstantDef:
"""
A constant definition within a module
"""
__slots__ = ('name', 'sourceref', 'type3', 'type5', 'constant', )
name: str
sourceref: SourceRef
type3: Type3
type5: type5typeexpr.TypeExpr
constant: Constant
def __init__(self, name: str, sourceref: SourceRef, type3: Type3, type5: type5typeexpr.TypeExpr, constant: Constant) -> None:
self.name = name
self.sourceref = sourceref
self.type3 = type3
self.type5 = type5
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
def __repr__(self) -> str:
return f'ModuleDataBlock({self.data!r}, {self.address!r})'
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[G]:
"""
A module is a file and consists of functions
"""
__slots__ = ('build', 'filename', 'data', 'types', 'type5s', 'struct_definitions', 'constant_defs', 'functions', 'methods', 'operators', 'functions_table', )
build: BuildBase[G]
filename: str
data: ModuleData
types: dict[str, Type3]
type5s: dict[str, type5typeexpr.TypeExpr]
struct_definitions: Dict[str, StructDefinition]
constant_defs: Dict[str, ModuleConstantDef]
functions: Dict[str, Function]
methods: Dict[str, Type3ClassMethod]
operators: Dict[str, Type3ClassMethod]
functions_table: dict[Function, int]
def __init__(self, build: BuildBase[G], filename: str) -> None:
self.build = build
self.filename = filename
self.data = ModuleData()
self.types = {}
self.type5s = {}
self.struct_definitions = {}
self.constant_defs = {}
self.functions = {}
self.methods = {}
self.operators = {}
self.functions_table = {}