diff --git a/src/pystencilssfg/composer/basic_composer.py b/src/pystencilssfg/composer/basic_composer.py index 76e2907361d054f7468279e2500469b408f0d477..08422bebbb685bad1220be9412a7ecff4491f8c9 100644 --- a/src/pystencilssfg/composer/basic_composer.py +++ b/src/pystencilssfg/composer/basic_composer.py @@ -28,7 +28,7 @@ from ..ir.postprocessing import ( SfgDeferredFieldMapping, SfgDeferredVectorMapping, ) -from ..ir.source_components import ( +from ..ir import ( SfgFunction, SfgKernelNamespace, SfgKernelHandle, diff --git a/src/pystencilssfg/composer/class_composer.py b/src/pystencilssfg/composer/class_composer.py index fa7d6f2583fd0de6539a67af13b67d05ae1029a1..3ed5c0fe0a432d3fbd8e2e7729a6d0f06a58104f 100644 --- a/src/pystencilssfg/composer/class_composer.py +++ b/src/pystencilssfg/composer/class_composer.py @@ -13,8 +13,8 @@ from ..lang import ( SfgVar, ) -from ..ir.call_tree import SfgCallTreeNode -from ..ir.source_components import ( +from ..ir import ( + SfgCallTreeNode, SfgClass, SfgConstructor, SfgMethod, diff --git a/src/pystencilssfg/context.py b/src/pystencilssfg/context.py index 48d0720c9927542bdca291c206f28f55f9172437..a129f982e36344410d5fdd58ae5501e112210bc0 100644 --- a/src/pystencilssfg/context.py +++ b/src/pystencilssfg/context.py @@ -2,14 +2,14 @@ from __future__ import annotations from typing import Sequence, Any, Generator from .config import CodeStyle -from .ir.source_components import ( +from .ir import ( SfgSourceFile, SfgNamespace, SfgNamespaceBlock, - SfgNamespaceElement, SfgCodeEntity, SfgGlobalNamespace, ) +from .ir.syntax import SfgNamespaceElement from .exceptions import SfgException diff --git a/src/pystencilssfg/extensions/sycl.py b/src/pystencilssfg/extensions/sycl.py index 88dbc9be2e215b1fdce5833ef18eac6eab336d74..a628f00802b7863eb2f67a9a84598e4aa1be4e01 100644 --- a/src/pystencilssfg/extensions/sycl.py +++ b/src/pystencilssfg/extensions/sycl.py @@ -17,8 +17,8 @@ from ..composer import ( SfgComposerMixIn, make_sequence, ) -from ..ir.source_components import SfgKernelHandle from ..ir import ( + SfgKernelHandle, SfgCallTreeNode, SfgCallTreeLeaf, SfgKernelCallNode, diff --git a/src/pystencilssfg/ir/__init__.py b/src/pystencilssfg/ir/__init__.py index f1760b7c9b9ecdaa4821adf29fbc9f2129e0bd46..8f03fed0d4c2467377cdaab6cf100a13f7ded9fb 100644 --- a/src/pystencilssfg/ir/__init__.py +++ b/src/pystencilssfg/ir/__init__.py @@ -14,20 +14,32 @@ from .call_tree import ( SfgSwitch, ) -from .source_components import ( +from .entities import ( + SfgCodeEntity, + SfgNamespace, + SfgGlobalNamespace, SfgKernelNamespace, SfgKernelHandle, - SfgKernelParamVar, SfgFunction, SfgVisibility, SfgClassKeyword, SfgClassMember, - SfgVisibilityBlock, SfgMemberVariable, SfgMethod, SfgConstructor, SfgClass, ) + +from .syntax import ( + SfgEntityDecl, + SfgEntityDef, + SfgVisibilityBlock, + SfgNamespaceBlock, + SfgClassBody, + SfgSourceFileType, + SfgSourceFile, +) + from .analysis import collect_includes __all__ = [ @@ -44,17 +56,25 @@ __all__ = [ "SfgBranch", "SfgSwitchCase", "SfgSwitch", + "SfgCodeEntity", + "SfgNamespace", + "SfgGlobalNamespace", "SfgKernelNamespace", "SfgKernelHandle", - "SfgKernelParamVar", "SfgFunction", "SfgVisibility", "SfgClassKeyword", "SfgClassMember", - "SfgVisibilityBlock", "SfgMemberVariable", "SfgMethod", "SfgConstructor", "SfgClass", - "collect_includes" + "SfgEntityDecl", + "SfgEntityDef", + "SfgVisibilityBlock", + "SfgNamespaceBlock", + "SfgClassBody", + "SfgSourceFileType", + "SfgSourceFile", + "collect_includes", ] diff --git a/src/pystencilssfg/ir/analysis.py b/src/pystencilssfg/ir/analysis.py index c550975cd0b5750f980f52145cbd2ee7e5a3f93a..c2c3e34675585568115d1a4a06f0867eb9ca563c 100644 --- a/src/pystencilssfg/ir/analysis.py +++ b/src/pystencilssfg/ir/analysis.py @@ -10,7 +10,7 @@ from ..lang import HeaderFile, includes def collect_includes(obj: Any) -> set[HeaderFile]: from ..context import SfgContext from .call_tree import SfgCallTreeNode - from .source_components import ( + from .entities import ( SfgFunction, SfgClass, SfgConstructor, diff --git a/src/pystencilssfg/ir/call_tree.py b/src/pystencilssfg/ir/call_tree.py index 9a29f2f0715d18878f7a84926504c51ebf78c213..2e057dd1b2864bfaf2845501cccf3ff10673640c 100644 --- a/src/pystencilssfg/ir/call_tree.py +++ b/src/pystencilssfg/ir/call_tree.py @@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Sequence, Iterable, NewType from abc import ABC, abstractmethod -from .source_components import SfgKernelHandle +from .entities import SfgKernelHandle from ..lang import SfgVar, HeaderFile if TYPE_CHECKING: diff --git a/src/pystencilssfg/ir/source_components.py b/src/pystencilssfg/ir/entities.py similarity index 68% rename from src/pystencilssfg/ir/source_components.py rename to src/pystencilssfg/ir/entities.py index b4d8aa77cbf769fb465460a54ace5755168a6d3e..9d76b39fbf68afe34f62f150aa32b4557be0a840 100644 --- a/src/pystencilssfg/ir/source_components.py +++ b/src/pystencilssfg/ir/entities.py @@ -6,9 +6,6 @@ from typing import ( TYPE_CHECKING, Sequence, Generator, - Iterable, - TypeVar, - Generic, ) from dataclasses import replace from itertools import chain @@ -17,7 +14,7 @@ from pystencils import CreateKernelConfig, create_kernel, Field from pystencils.codegen import Kernel from pystencils.types import PsType, PsCustomType -from ..lang import SfgVar, SfgKernelParamVar, HeaderFile, void +from ..lang import SfgVar, SfgKernelParamVar, void from ..exceptions import SfgException if TYPE_CHECKING: @@ -423,9 +420,6 @@ class SfgClass(SfgCodeEntity): self._class_keyword = class_keyword self._bases_classes = tuple(bases) - self._default_block = SfgVisibilityBlock(SfgVisibility.DEFAULT) - self._blocks = [self._default_block] - self._constructors: list[SfgConstructor] = [] self._methods: list[SfgMethod] = [] self._member_vars: dict[str, SfgMemberVariable] = dict() @@ -443,30 +437,15 @@ class SfgClass(SfgCodeEntity): def class_keyword(self) -> SfgClassKeyword: return self._class_keyword - @property - def default(self) -> SfgVisibilityBlock: - return self._default_block - - def append_visibility_block(self, block: SfgVisibilityBlock): - if block.visibility == SfgVisibility.DEFAULT: - raise SfgException( - "Can't add another block with DEFAULT visibility to a class. Use `.default` instead." - ) - self._blocks.append(block) - - def visibility_blocks(self) -> tuple[SfgVisibilityBlock, ...]: - return tuple(self._blocks) - def members( self, visibility: SfgVisibility | None = None ) -> Generator[SfgClassMember, None, None]: if visibility is None: - yield from chain.from_iterable(b.members() for b in self._blocks) - else: - yield from chain.from_iterable( - b.members() - for b in filter(lambda b: b.visibility == visibility, self._blocks) + yield from chain( + self._constructors, self._methods, self._member_vars.values() ) + else: + yield from filter(lambda m: m.visibility == visibility, self.members()) def member_variables( self, visibility: SfgVisibility | None = None @@ -511,186 +490,3 @@ class SfgClass(SfgCodeEntity): ) self._member_vars[variable.name] = variable - - -# ========================================================================================================= -# -# SYNTACTICAL ELEMENTS -# -# These classes model *code elements*, which represent the actual syntax objects that populate the output -# files, their namespaces and class bodies. -# -# ========================================================================================================= - - -SourceEntity_T = TypeVar( - "SourceEntity_T", bound=SfgKernelHandle | SfgFunction | SfgClassMember | SfgClass, covariant=True -) -"""Source entities that may have declarations and definitions.""" - - -class SfgEntityDecl(Generic[SourceEntity_T]): - """Declaration of a function, class, method, or constructor""" - - __match_args__ = ("entity",) - - def __init__(self, entity: SourceEntity_T) -> None: - self._entity = entity - - @property - def entity(self) -> SourceEntity_T: - return self._entity - - -class SfgEntityDef(Generic[SourceEntity_T]): - """Definition of a function, class, method, or constructor""" - - __match_args__ = ("entity",) - - def __init__(self, entity: SourceEntity_T) -> None: - self._entity = entity - - @property - def entity(self) -> SourceEntity_T: - return self._entity - - -SfgClassBodyElement = ( - str - | SfgEntityDecl[SfgClassMember] - | SfgEntityDef[SfgClassMember] - | SfgMemberVariable -) -"""Elements that may be placed in the visibility blocks of a class body.""" - - -class SfgVisibilityBlock: - """Visibility-qualified block inside a class definition body. - - Visibility blocks host the code elements placed inside a class body: - method and constructor declarations, - in-class method and constructor definitions, - as well as variable declarations and definitions. - - Args: - visibility: The visibility qualifier of this block - """ - - def __init__(self, visibility: SfgVisibility) -> None: - self._vis = visibility - self._elements: list[SfgClassBodyElement] = [] - self._cls: SfgClass | None = None - - @property - def visibility(self) -> SfgVisibility: - return self._vis - - @property - def elements(self) -> list[SfgClassBodyElement]: - return self._elements - - @elements.setter - def elements(self, elems: Iterable[SfgClassBodyElement]): - self._elements = list(elems) - - def members(self) -> Generator[SfgClassMember, None, None]: - for elem in self._elements: - match elem: - case SfgEntityDecl(entity) | SfgEntityDef(entity): - yield entity - case SfgMemberVariable(): - yield elem - - -class SfgNamespaceBlock: - """A C++ namespace. - - Each namespace has a `name` and a `parent`; its fully qualified name is given as - ``<parent.name>::<name>``. - - Args: - name: Local name of this namespace - parent: Parent namespace enclosing this namespace - """ - - def __init__(self, namespace: SfgNamespace) -> None: - self._namespace = namespace - self._elements: list[SfgNamespaceElement] = [] - - @property - def namespace(self) -> SfgNamespace: - return self._namespace - - @property - def elements(self) -> list[SfgNamespaceElement]: - """Sequence of source elements that make up the body of this namespace""" - return self._elements - - @elements.setter - def elements(self, elems: Iterable[SfgNamespaceElement]): - self._elements = list(elems) - - -SfgNamespaceElement = str | SfgNamespaceBlock | SfgEntityDecl | SfgEntityDef -"""Elements that may be placed inside a namespace, including the global namespace.""" - - -class SfgSourceFileType(Enum): - HEADER = auto() - TRANSLATION_UNIT = auto() - - -class SfgSourceFile: - """A C++ source file. - - Args: - name: Name of the file (without parent directories), e.g. ``Algorithms.cpp`` - file_type: Type of the source file (header or translation unit) - prelude: Optionally, text of the prelude comment printed at the top of the file - """ - - def __init__( - self, name: str, file_type: SfgSourceFileType, prelude: str | None = None - ) -> None: - self._name: str = name - self._file_type: SfgSourceFileType = file_type - self._prelude: str | None = prelude - self._includes: list[HeaderFile] = [] - self._elements: list[SfgNamespaceElement] = [] - - @property - def name(self) -> str: - """Name of this source file""" - return self._name - - @property - def file_type(self) -> SfgSourceFileType: - """File type of this source file""" - return self._file_type - - @property - def prelude(self) -> str | None: - """Text of the prelude comment""" - return self._prelude - - @prelude.setter - def prelude(self, text: str | None): - self._prelude = text - - @property - def includes(self) -> list[HeaderFile]: - """Sequence of header files to be included at the top of this file""" - return self._includes - - @includes.setter - def includes(self, incl: Iterable[HeaderFile]): - self._includes = list(incl) - - @property - def elements(self) -> list[SfgNamespaceElement]: - """Sequence of source elements comprising the body of this file""" - return self._elements - - @elements.setter - def elements(self, elems: Iterable[SfgNamespaceElement]): - self._elements = list(elems) diff --git a/src/pystencilssfg/ir/postprocessing.py b/src/pystencilssfg/ir/postprocessing.py index db26a38ba2ffd189edb91156e6f0dc95cf29c616..ca6d9f21b8d91230053b4d06a93698d357c17e5e 100644 --- a/src/pystencilssfg/ir/postprocessing.py +++ b/src/pystencilssfg/ir/postprocessing.py @@ -15,7 +15,7 @@ from pystencils.codegen.properties import FieldBasePtr, FieldShape, FieldStride from ..exceptions import SfgException from .call_tree import SfgCallTreeNode, SfgCallTreeLeaf, SfgSequence, SfgStatements -from ..ir.source_components import SfgKernelParamVar +from ..lang.expressions import SfgKernelParamVar from ..lang import ( SfgVar, IFieldExtraction, diff --git a/src/pystencilssfg/ir/syntax.py b/src/pystencilssfg/ir/syntax.py new file mode 100644 index 0000000000000000000000000000000000000000..2e924a032fe8c33d756a59fc62f9b5e6a2fdc732 --- /dev/null +++ b/src/pystencilssfg/ir/syntax.py @@ -0,0 +1,228 @@ +from __future__ import annotations + +from enum import Enum, auto +from typing import ( + Generator, + Iterable, + TypeVar, + Generic, +) + +from ..lang import HeaderFile + +from .entities import ( + SfgNamespace, + SfgKernelHandle, + SfgFunction, + SfgClassMember, + SfgMemberVariable, + SfgVisibility, + SfgClass, +) + +# ========================================================================================================= +# +# SYNTACTICAL ELEMENTS +# +# These classes model *code elements*, which represent the actual syntax objects that populate the output +# files, their namespaces and class bodies. +# +# ========================================================================================================= + + +SourceEntity_T = TypeVar( + "SourceEntity_T", + bound=SfgKernelHandle | SfgFunction | SfgClassMember | SfgClass, + covariant=True, +) +"""Source entities that may have declarations and definitions.""" + + +class SfgEntityDecl(Generic[SourceEntity_T]): + """Declaration of a function, class, method, or constructor""" + + __match_args__ = ("entity",) + + def __init__(self, entity: SourceEntity_T) -> None: + self._entity = entity + + @property + def entity(self) -> SourceEntity_T: + return self._entity + + +class SfgEntityDef(Generic[SourceEntity_T]): + """Definition of a function, class, method, or constructor""" + + __match_args__ = ("entity",) + + def __init__(self, entity: SourceEntity_T) -> None: + self._entity = entity + + @property + def entity(self) -> SourceEntity_T: + return self._entity + + +SfgClassBodyElement = ( + str + | SfgEntityDecl[SfgClassMember] + | SfgEntityDef[SfgClassMember] + | SfgMemberVariable +) +"""Elements that may be placed in the visibility blocks of a class body.""" + + +class SfgVisibilityBlock: + """Visibility-qualified block inside a class definition body. + + Visibility blocks host the code elements placed inside a class body: + method and constructor declarations, + in-class method and constructor definitions, + as well as variable declarations and definitions. + + Args: + visibility: The visibility qualifier of this block + """ + + def __init__(self, visibility: SfgVisibility) -> None: + self._vis = visibility + self._elements: list[SfgClassBodyElement] = [] + self._cls: SfgClass | None = None + + @property + def visibility(self) -> SfgVisibility: + return self._vis + + @property + def elements(self) -> list[SfgClassBodyElement]: + return self._elements + + @elements.setter + def elements(self, elems: Iterable[SfgClassBodyElement]): + self._elements = list(elems) + + def members(self) -> Generator[SfgClassMember, None, None]: + for elem in self._elements: + match elem: + case SfgEntityDecl(entity) | SfgEntityDef(entity): + yield entity + case SfgMemberVariable(): + yield elem + + +class SfgNamespaceBlock: + """A C++ namespace. + + Each namespace has a `name` and a `parent`; its fully qualified name is given as + ``<parent.name>::<name>``. + + Args: + name: Local name of this namespace + parent: Parent namespace enclosing this namespace + """ + + def __init__(self, namespace: SfgNamespace) -> None: + self._namespace = namespace + self._elements: list[SfgNamespaceElement] = [] + + @property + def namespace(self) -> SfgNamespace: + return self._namespace + + @property + def elements(self) -> list[SfgNamespaceElement]: + """Sequence of source elements that make up the body of this namespace""" + return self._elements + + @elements.setter + def elements(self, elems: Iterable[SfgNamespaceElement]): + self._elements = list(elems) + + +class SfgClassBody: + """Body of a class definition.""" + + def __init__(self, cls: SfgClass) -> None: + self._cls = cls + self._default_block = SfgVisibilityBlock(SfgVisibility.DEFAULT) + self._blocks = [self._default_block] + + @property + def default(self) -> SfgVisibilityBlock: + return self._default_block + + def append_visibility_block(self, block: SfgVisibilityBlock): + if block.visibility == SfgVisibility.DEFAULT: + raise ValueError( + "Can't add another block with DEFAULT visibility to this class body." + ) + self._blocks.append(block) + + def visibility_blocks(self) -> tuple[SfgVisibilityBlock, ...]: + return tuple(self._blocks) + + +SfgNamespaceElement = str | SfgNamespaceBlock | SfgEntityDecl | SfgEntityDef +"""Elements that may be placed inside a namespace, including the global namespace.""" + + +class SfgSourceFileType(Enum): + HEADER = auto() + TRANSLATION_UNIT = auto() + + +class SfgSourceFile: + """A C++ source file. + + Args: + name: Name of the file (without parent directories), e.g. ``Algorithms.cpp`` + file_type: Type of the source file (header or translation unit) + prelude: Optionally, text of the prelude comment printed at the top of the file + """ + + def __init__( + self, name: str, file_type: SfgSourceFileType, prelude: str | None = None + ) -> None: + self._name: str = name + self._file_type: SfgSourceFileType = file_type + self._prelude: str | None = prelude + self._includes: list[HeaderFile] = [] + self._elements: list[SfgNamespaceElement] = [] + + @property + def name(self) -> str: + """Name of this source file""" + return self._name + + @property + def file_type(self) -> SfgSourceFileType: + """File type of this source file""" + return self._file_type + + @property + def prelude(self) -> str | None: + """Text of the prelude comment""" + return self._prelude + + @prelude.setter + def prelude(self, text: str | None): + self._prelude = text + + @property + def includes(self) -> list[HeaderFile]: + """Sequence of header files to be included at the top of this file""" + return self._includes + + @includes.setter + def includes(self, incl: Iterable[HeaderFile]): + self._includes = list(incl) + + @property + def elements(self) -> list[SfgNamespaceElement]: + """Sequence of source elements comprising the body of this file""" + return self._elements + + @elements.setter + def elements(self, elems: Iterable[SfgNamespaceElement]): + self._elements = list(elems)