""" Contains the syntax tree for ourlang """ from typing import Dict, Iterable, List, Optional, Union from . import prelude from .type3.functions import FunctionSignature, TypeVariableContext from .type3.placeholders import PlaceholderForType, Type3OrPlaceholder from .type3.typeclasses import Type3ClassMethod from .type3.types import Type3 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: Type3ClassMethod left: Expression right: Expression def __init__(self, operator: 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', Type3ClassMethod] arguments: List[Expression] def __init__(self, function: Union['Function', 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: Type3OrPlaceholder member: str def __init__(self, varref: VariableReference, struct_type3: Type3OrPlaceholder, member: str) -> None: super().__init__() self.varref = varref self.struct_type3 = struct_type3 self.member = member 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: Type3) -> None: self.name = name self.type3 = type3 class Function: """ A function processes input and produces output """ __slots__ = ('name', 'lineno', 'exported', 'imported', 'statements', 'signature', 'returns_type3', 'posonlyargs', ) name: str lineno: int exported: bool imported: Optional[str] statements: List[Statement] signature: FunctionSignature 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.signature = FunctionSignature(TypeVariableContext(), []) self.returns_type3 = prelude.none # FIXME: This could be a placeholder self.posonlyargs = [] class StructDefinition: """ The definition for a struct """ __slots__ = ('struct_type3', 'lineno', ) struct_type3: Type3 lineno: int def __init__(self, struct_type3: Type3, 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: Type3 def __init__(self, struct_type3: Type3) -> None: super().__init__(f'@{struct_type3.name}@__init___@', -1) st_args = prelude.struct.did_construct(struct_type3) assert st_args is not None for mem, typ in st_args.items(): self.posonlyargs.append(FunctionParam(mem, typ, )) self.signature.args.append(typ) self.returns_type3 = struct_type3 self.signature.args.append(struct_type3) 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', 'operators', ) data: ModuleData types: dict[str, Type3] struct_definitions: Dict[str, StructDefinition] constant_defs: Dict[str, ModuleConstantDef] functions: Dict[str, Function] operators: Dict[str, Type3ClassMethod] def __init__(self) -> None: self.data = ModuleData() self.types = {} self.struct_definitions = {} self.constant_defs = {} self.functions = {} self.operators = {}