Skip to content
Snippets Groups Projects
context.py 7 KiB
Newer Older
from typing import Generator, Union, Optional, Sequence
Frederik Hennig's avatar
Frederik Hennig committed

Frederik Hennig's avatar
Frederik Hennig committed
import os
Frederik Hennig's avatar
Frederik Hennig committed

from pystencils import Field
Frederik Hennig's avatar
Frederik Hennig committed
from pystencils.astnodes import KernelFunction

from .configuration import SfgConfiguration, config_from_commandline, merge_configurations, SfgCodeStyle
Frederik Hennig's avatar
Frederik Hennig committed
from .kernel_namespace import SfgKernelNamespace, SfgKernelHandle
Frederik Hennig's avatar
Frederik Hennig committed
from .tree import SfgCallTreeNode, SfgKernelCallNode, SfgStatements
from .tree.deferred_nodes import SfgDeferredFieldMapping
from .tree.builders import SfgBranchBuilder, make_sequence
from .tree.visitors import CollectIncludes
from .source_concepts import SrcField, TypedSymbolOrObject
from .source_components import SfgFunction, SfgHeaderInclude
class SourceFileGenerator:
Frederik Hennig's avatar
Frederik Hennig committed
    def __init__(self, sfg_config: SfgConfiguration | None = None):
Frederik Hennig's avatar
Frederik Hennig committed
        if sfg_config and not isinstance(sfg_config, SfgConfiguration):
            raise TypeError("sfg_config is not an SfgConfiguration.")

        import __main__
        scriptpath = __main__.__file__
        scriptname = path.split(scriptpath)[1]
        basename = path.splitext(scriptname)[0]

        project_config, cmdline_config, script_args = config_from_commandline(sys.argv)

        config = merge_configurations(project_config, cmdline_config, sfg_config)
        self._context = SfgContext(script_args, config)

        from .emitters.cpu.basic_cpu import BasicCpuEmitter
Frederik Hennig's avatar
Frederik Hennig committed
        self._emitter = BasicCpuEmitter(basename, config)
Frederik Hennig's avatar
Frederik Hennig committed

    def clean_files(self):
        for file in self._emitter.output_files:
Frederik Hennig's avatar
Frederik Hennig committed
            if path.exists(file):
                os.remove(file)
Frederik Hennig's avatar
Frederik Hennig committed
        self.clean_files()
Frederik Hennig's avatar
Frederik Hennig committed
    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is None:
Frederik Hennig's avatar
Frederik Hennig committed
            self._emitter.write_files(self._context)
    def __init__(self, argv, config: SfgConfiguration):
        self._config = config
        self._default_kernel_namespace = SfgKernelNamespace(self, "kernels")

        self._code_namespace = None

Frederik Hennig's avatar
Frederik Hennig committed
        #   Source Components
Frederik Hennig's avatar
Frederik Hennig committed
        self._includes: set[SfgHeaderInclude] = set()
Frederik Hennig's avatar
Frederik Hennig committed
        self._kernel_namespaces = {self._default_kernel_namespace.name: self._default_kernel_namespace}
Frederik Hennig's avatar
Frederik Hennig committed
        self._functions: dict[str, SfgFunction] = dict()
Frederik Hennig's avatar
Frederik Hennig committed

    @property
    def argv(self) -> Sequence[str]:
        return self._argv
Frederik Hennig's avatar
Frederik Hennig committed
    def root_namespace(self) -> str | None:
        return self._config.base_namespace
    @property
Frederik Hennig's avatar
Frederik Hennig committed
    def inner_namespace(self) -> str | None:
        return self._code_namespace

    @property
Frederik Hennig's avatar
Frederik Hennig committed
    def fully_qualified_namespace(self) -> str | None:
        match (self.root_namespace, self.inner_namespace):
            case None, None: return None
            case outer, None: return outer
            case None, inner: return inner
            case outer, inner: return f"{outer}::{inner}"
Frederik Hennig's avatar
Frederik Hennig committed
            case _: assert False
Frederik Hennig's avatar
Frederik Hennig committed
    @property
    def codestyle(self) -> SfgCodeStyle:
Frederik Hennig's avatar
Frederik Hennig committed
        assert self._config.codestyle is not None
        return self._config.codestyle
Frederik Hennig's avatar
Frederik Hennig committed
    # ----------------------------------------------------------------------------------------------
Frederik Hennig's avatar
Frederik Hennig committed
    # ----------------------------------------------------------------------------------------------

    def includes(self) -> Generator[SfgHeaderInclude, None, None]:
        yield from self._includes

    def kernel_namespaces(self) -> Generator[SfgKernelNamespace, None, None]:
        yield from self._kernel_namespaces.values()

    def functions(self) -> Generator[SfgFunction, None, None]:
        yield from self._functions.values()

Frederik Hennig's avatar
Frederik Hennig committed
    # ----------------------------------------------------------------------------------------------
Frederik Hennig's avatar
Frederik Hennig committed
    # ----------------------------------------------------------------------------------------------

    def add_include(self, include: SfgHeaderInclude):
        self._includes.add(include)

    def add_function(self, func: SfgFunction):
        if func.name in self._functions:
            raise ValueError(f"Duplicate function: {func.name}")
        self._functions[func.name] = func
        for incl in CollectIncludes().visit(func._tree):
            self.add_include(incl)

Frederik Hennig's avatar
Frederik Hennig committed
    # ----------------------------------------------------------------------------------------------
Frederik Hennig's avatar
Frederik Hennig committed
    # ----------------------------------------------------------------------------------------------
Frederik Hennig's avatar
Frederik Hennig committed
    def kernels(self) -> SfgKernelNamespace:
        return self._default_kernel_namespace

Frederik Hennig's avatar
Frederik Hennig committed
    def kernel_namespace(self, name: str) -> SfgKernelNamespace:
        if name in self._kernel_namespaces:
            raise ValueError(f"Duplicate kernel namespace: {name}")

        kns = SfgKernelNamespace(self, name)
        self._kernel_namespaces[name] = kns
        return kns
Frederik Hennig's avatar
Frederik Hennig committed

    def include(self, header_file: str):
        system_header = False
        if header_file.startswith("<") and header_file.endswith(">"):
            header_file = header_file[1:-1]
            system_header = True
        self.add_include(SfgHeaderInclude(header_file, system_header=system_header))
Frederik Hennig's avatar
Frederik Hennig committed

Frederik Hennig's avatar
Frederik Hennig committed
    def function(self,
Frederik Hennig's avatar
Frederik Hennig committed
                 name: str,
Frederik Hennig's avatar
Frederik Hennig committed
                 ast_or_kernel_handle: Optional[Union[KernelFunction, SfgKernelHandle]] = None):
Frederik Hennig's avatar
Frederik Hennig committed
        if name in self._functions:
            raise ValueError(f"Duplicate function: {name}")
Frederik Hennig's avatar
Frederik Hennig committed
        if ast_or_kernel_handle is not None:
            if isinstance(ast_or_kernel_handle, KernelFunction):
                khandle = self._default_kernel_namespace.add(ast_or_kernel_handle)
Frederik Hennig's avatar
Frederik Hennig committed
                tree = SfgKernelCallNode(khandle)
Frederik Hennig's avatar
Frederik Hennig committed
            elif isinstance(ast_or_kernel_handle, SfgKernelCallNode):
                tree = ast_or_kernel_handle
            else:
Frederik Hennig's avatar
Frederik Hennig committed
                raise TypeError("Invalid type of argument `ast_or_kernel_handle`!")

            func = SfgFunction(self, name, tree)
            self.add_function(func)
Frederik Hennig's avatar
Frederik Hennig committed
        else:
            def sequencer(*args: SfgCallTreeNode):
                tree = make_sequence(*args)
Frederik Hennig's avatar
Frederik Hennig committed
                func = SfgFunction(self, name, tree)
Frederik Hennig's avatar
Frederik Hennig committed

            return sequencer

Frederik Hennig's avatar
Frederik Hennig committed
    # ----------------------------------------------------------------------------------------------
    #   In-Sequence builders to be used within the second phase of SfgContext.function().
Frederik Hennig's avatar
Frederik Hennig committed
    # ----------------------------------------------------------------------------------------------
Frederik Hennig's avatar
Frederik Hennig committed

    def call(self, kernel_handle: SfgKernelHandle) -> SfgKernelCallNode:
        return SfgKernelCallNode(kernel_handle)
Frederik Hennig's avatar
Frederik Hennig committed
    @property
    def branch(self) -> SfgBranchBuilder:
Frederik Hennig's avatar
Frederik Hennig committed
    def map_field(self, field: Field, src_object: Optional[SrcField] = None) -> SfgDeferredFieldMapping:
        if src_object is None:
            raise NotImplementedError("Automatic field extraction is not implemented yet.")
        else:
            return SfgDeferredFieldMapping(field, src_object)
    def map_param(self, lhs: TypedSymbolOrObject, rhs: TypedSymbolOrObject, mapping: str):
        return SfgStatements(mapping, (lhs,), (rhs,))