diff --git a/integration/test_classes.py b/integration/test_classes.py
index ecd6b89510485827ae4b0a8ffcbe1f0ccf9f634f..39421001743bbd84564a5cbbfb5ef50953b597bf 100644
--- a/integration/test_classes.py
+++ b/integration/test_classes.py
@@ -1,6 +1,7 @@
 # type: ignore
 from pystencilssfg import SourceFileGenerator, SfgConfiguration, SfgComposer
 from pystencilssfg.configuration import SfgCodeStyle
+from pystencilssfg.types import SrcType
 from pystencilssfg.source_concepts import SrcObject
 from pystencilssfg.source_components import SfgClass, SfgMemberVariable, SfgConstructor, SfgMethod, SfgVisibility
 
@@ -30,18 +31,45 @@ with SourceFileGenerator(sfg_config) as ctx:
     cls.add_method(SfgMethod(
         "callKernel",
         sfg.call(khandle),
+        cls,
         visibility=SfgVisibility.PUBLIC
     ))
 
+    cls.add_method(SfgMethod(
+        "inlineConst",
+        sfg.seq(
+            "return -1.0;"
+        ),
+        cls,
+        visibility=SfgVisibility.PUBLIC,
+        return_type=SrcType("double"),
+        inline=True,
+        const=True
+    ))
+
+    cls.add_method(SfgMethod(
+        "awesomeMethod",
+        sfg.seq(
+            "return 2.0f;"
+        ),
+        cls,
+        visibility=SfgVisibility.PRIVATE,
+        return_type=SrcType("float"),
+        inline=False,
+        const=True
+    ))
+
     cls.add_member_variable(
         SfgMemberVariable(
             "stuff", "std::vector< int >",
+            cls,
             SfgVisibility.PRIVATE
         )
     )
 
     cls.add_constructor(
         SfgConstructor(
+            cls,
             [SrcObject("std::vector< int > &", "stuff")],
             ["stuff_(stuff)"],
             visibility=SfgVisibility.PUBLIC
diff --git a/pdm.lock b/pdm.lock
index 315541a523f73d4afdf538ef3db0901aa3f34e12..c6638a202638b423a78dee411100e6da56792cce 100644
--- a/pdm.lock
+++ b/pdm.lock
@@ -2,10 +2,10 @@
 # It is not intended for manual editing.
 
 [metadata]
-groups = ["default", "docs", "interactive", "code_quality"]
+groups = ["default", "code_quality", "docs", "interactive"]
 strategy = ["cross_platform"]
 lock_version = "4.4"
-content_hash = "sha256:f9e6e0eed785eecd687dfee3afe479681a2082cee5c00285e1975fbf8b7d50df"
+content_hash = "sha256:2c854f8da4b29c3080cd89c774409f95c47d3532c953cf10ecaa67d0b77ff9cf"
 
 [[package]]
 name = "appdirs"
@@ -16,15 +16,6 @@ files = [
     {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
 ]
 
-[[package]]
-name = "appnope"
-version = "0.1.3"
-summary = "Disable App Nap on macOS >= 10.9"
-files = [
-    {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"},
-    {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"},
-]
-
 [[package]]
 name = "asttokens"
 version = "2.4.1"
@@ -210,35 +201,34 @@ files = [
 
 [[package]]
 name = "idna"
-version = "3.4"
+version = "3.6"
 requires_python = ">=3.5"
 summary = "Internationalized Domain Names in Applications (IDNA)"
 files = [
-    {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
-    {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
+    {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"},
+    {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"},
 ]
 
 [[package]]
 name = "ipython"
-version = "8.17.2"
+version = "8.18.1"
 requires_python = ">=3.9"
 summary = "IPython: Productive Interactive Computing"
 dependencies = [
-    "appnope; sys_platform == \"darwin\"",
     "colorama; sys_platform == \"win32\"",
     "decorator",
     "exceptiongroup; python_version < \"3.11\"",
     "jedi>=0.16",
     "matplotlib-inline",
     "pexpect>4.3; sys_platform != \"win32\"",
-    "prompt-toolkit!=3.0.37,<3.1.0,>=3.0.30",
+    "prompt-toolkit<3.1.0,>=3.0.41",
     "pygments>=2.4.0",
     "stack-data",
     "traitlets>=5",
 ]
 files = [
-    {file = "ipython-8.17.2-py3-none-any.whl", hash = "sha256:1e4d1d666a023e3c93585ba0d8e962867f7a111af322efff6b9c58062b3e5444"},
-    {file = "ipython-8.17.2.tar.gz", hash = "sha256:126bb57e1895594bb0d91ea3090bbd39384f6fe87c3d57fd558d0670f50339bb"},
+    {file = "ipython-8.18.1-py3-none-any.whl", hash = "sha256:e8267419d72d81955ec1177f8a29aaa90ac80ad647499201119e2f05e99aa397"},
+    {file = "ipython-8.18.1.tar.gz", hash = "sha256:ca6f079bb33457c66e233e4580ebfc4128855b4cf6370dddd73842a9563e8a27"},
 ]
 
 [[package]]
@@ -400,7 +390,7 @@ files = [
 
 [[package]]
 name = "mkdocs-material"
-version = "9.4.11"
+version = "9.4.14"
 requires_python = ">=3.8"
 summary = "Documentation that simply works"
 dependencies = [
@@ -417,18 +407,18 @@ dependencies = [
     "requests~=2.26",
 ]
 files = [
-    {file = "mkdocs_material-9.4.11-py3-none-any.whl", hash = "sha256:794b81d74df4fd7dee952dd4502f7b6a7913a1fc56021e5f36f8e96eb20ffb25"},
-    {file = "mkdocs_material-9.4.11.tar.gz", hash = "sha256:82c2bdbdc8445854f400d12831a8b0f7602efaaead7b264ac3c45aa3aa240755"},
+    {file = "mkdocs_material-9.4.14-py3-none-any.whl", hash = "sha256:dbc78a4fea97b74319a6aa9a2f0be575a6028be6958f813ba367188f7b8428f6"},
+    {file = "mkdocs_material-9.4.14.tar.gz", hash = "sha256:a511d3ff48fa8718b033e7e37d17abd9cc1de0fdf0244a625ca2ae2387e2416d"},
 ]
 
 [[package]]
 name = "mkdocs-material-extensions"
-version = "1.3"
+version = "1.3.1"
 requires_python = ">=3.8"
 summary = "Extension pack for Python Markdown and MkDocs Material."
 files = [
-    {file = "mkdocs_material_extensions-1.3-py3-none-any.whl", hash = "sha256:0297cc48ba68a9fdd1ef3780a3b41b534b0d0df1d1181a44676fda5f464eeadc"},
-    {file = "mkdocs_material_extensions-1.3.tar.gz", hash = "sha256:f0446091503acb110a7cab9349cbc90eeac51b58d1caa92a704a81ca1e24ddbd"},
+    {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"},
+    {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"},
 ]
 
 [[package]]
@@ -605,14 +595,14 @@ files = [
 
 [[package]]
 name = "pexpect"
-version = "4.8.0"
+version = "4.9.0"
 summary = "Pexpect allows easy control of interactive console applications."
 dependencies = [
     "ptyprocess>=0.5",
 ]
 files = [
-    {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"},
-    {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"},
+    {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"},
+    {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"},
 ]
 
 [[package]]
@@ -688,16 +678,16 @@ files = [
 
 [[package]]
 name = "pymdown-extensions"
-version = "10.4"
+version = "10.5"
 requires_python = ">=3.8"
 summary = "Extension pack for Python Markdown."
 dependencies = [
-    "markdown>=3.2",
+    "markdown>=3.5",
     "pyyaml",
 ]
 files = [
-    {file = "pymdown_extensions-10.4-py3-none-any.whl", hash = "sha256:cfc28d6a09d19448bcbf8eee3ce098c7d17ff99f7bd3069db4819af181212037"},
-    {file = "pymdown_extensions-10.4.tar.gz", hash = "sha256:bc46f11749ecd4d6b71cf62396104b4a200bad3498cb0f5dad1b8502fe461a35"},
+    {file = "pymdown_extensions-10.5-py3-none-any.whl", hash = "sha256:1f0ca8bb5beff091315f793ee17683bc1390731f6ac4c5eb01e27464b80fe879"},
+    {file = "pymdown_extensions-10.5.tar.gz", hash = "sha256:1b60f1e462adbec5a1ed79dac91f666c9c0d241fa294de1989f29d20096cfd0b"},
 ]
 
 [[package]]
@@ -899,12 +889,12 @@ files = [
 
 [[package]]
 name = "traitlets"
-version = "5.13.0"
+version = "5.14.0"
 requires_python = ">=3.8"
 summary = "Traitlets Python configuration system"
 files = [
-    {file = "traitlets-5.13.0-py3-none-any.whl", hash = "sha256:baf991e61542da48fe8aef8b779a9ea0aa38d8a54166ee250d5af5ecf4486619"},
-    {file = "traitlets-5.13.0.tar.gz", hash = "sha256:9b232b9430c8f57288c1024b34a8f0251ddcc47268927367a0dd3eeaca40deb5"},
+    {file = "traitlets-5.14.0-py3-none-any.whl", hash = "sha256:f14949d23829023013c47df20b4a76ccd1a85effb786dc060f34de7948361b33"},
+    {file = "traitlets-5.14.0.tar.gz", hash = "sha256:fcdaa8ac49c04dfa0ed3ee3384ef6dfdb5d6f3741502be247279407679296772"},
 ]
 
 [[package]]
diff --git a/pyproject.toml b/pyproject.toml
index cc7875a9af6fe60f18b6e9265c3ca7c18a047f7d..85ad9662ac2ef54325bf442ed8d5d6f63cd26674 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,7 +5,6 @@ authors = [
     {name = "Frederik Hennig", email = "frederik.hennig@fau.de"},
 ]
 dependencies = [
-    "jinja2>=3.1.2",
     "pystencils>=1.3.2",
 ]
 requires-python = ">=3.10"
diff --git a/src/pystencilssfg/cli.py b/src/pystencilssfg/cli.py
index 972aae13259182b66524ccaef3845dbf30aad8e1..933c28a457dd4a25f2a4a1f5c794646ff1f7c000 100644
--- a/src/pystencilssfg/cli.py
+++ b/src/pystencilssfg/cli.py
@@ -72,7 +72,7 @@ def list_files(args):
     _, scriptname = path.split(args.codegen_script)
     basename = path.splitext(scriptname)[0]
 
-    from .emitters import HeaderSourcePairEmitter
+    from .emission import HeaderSourcePairEmitter
 
     emitter = HeaderSourcePairEmitter(config.get_output_spec(basename))
 
diff --git a/src/pystencilssfg/context.py b/src/pystencilssfg/context.py
index 48ecfd2bb8368f9d534ca8c753d229333f8178cc..69fa58dab860863e5d987aa651ca581ef03b29a0 100644
--- a/src/pystencilssfg/context.py
+++ b/src/pystencilssfg/context.py
@@ -36,6 +36,10 @@ class SfgContext:
         self._functions: dict[str, SfgFunction] = dict()
         self._classes: dict[str, SfgClass] = dict()
 
+        #   Standard stuff
+        self.add_include(SfgHeaderInclude("cstdint", system_header=True))
+        self.add_definition("#define RESTRICT __restrict__")
+
     @property
     def argv(self) -> Sequence[str]:
         """If this context was created by a `pystencilssfg.SourceFileGenerator`, provides the command
diff --git a/src/pystencilssfg/emitters/__init__.py b/src/pystencilssfg/emission/__init__.py
similarity index 100%
rename from src/pystencilssfg/emitters/__init__.py
rename to src/pystencilssfg/emission/__init__.py
diff --git a/src/pystencilssfg/emitters/clang_format.py b/src/pystencilssfg/emission/clang_format.py
similarity index 100%
rename from src/pystencilssfg/emitters/clang_format.py
rename to src/pystencilssfg/emission/clang_format.py
diff --git a/src/pystencilssfg/emission/header_source_pair.py b/src/pystencilssfg/emission/header_source_pair.py
new file mode 100644
index 0000000000000000000000000000000000000000..b21b9952a7c77c82187cdbdb8fb9e2ee2ce1c8dd
--- /dev/null
+++ b/src/pystencilssfg/emission/header_source_pair.py
@@ -0,0 +1,42 @@
+from os import path, makedirs
+
+from ..configuration import SfgOutputSpec
+from ..context import SfgContext
+from .printers import SfgHeaderPrinter, SfgImplPrinter
+
+from .clang_format import invoke_clang_format
+
+
+class HeaderSourcePairEmitter:
+    def __init__(self, output_spec: SfgOutputSpec):
+        self._basename = output_spec.basename
+        self._output_directory = output_spec.output_directory
+        self._header_filename = output_spec.get_header_filename()
+        self._impl_filename = output_spec.get_impl_filename()
+
+        self._ospec = output_spec
+
+    @property
+    def output_files(self) -> tuple[str, str]:
+        return (
+            path.join(self._output_directory, self._header_filename),
+            path.join(self._output_directory, self._impl_filename)
+        )
+
+    def write_files(self, ctx: SfgContext):
+        header_printer = SfgHeaderPrinter(ctx, self._ospec)
+        impl_printer = SfgImplPrinter(ctx, self._ospec)
+
+        header = header_printer.get_code()
+        impl = impl_printer.get_code()
+
+        header = invoke_clang_format(header, ctx.codestyle)
+        impl = invoke_clang_format(impl, ctx.codestyle)
+
+        makedirs(self._output_directory, exist_ok=True)
+
+        with open(self._ospec.get_header_filepath(), 'w') as headerfile:
+            headerfile.write(header)
+
+        with open(self._ospec.get_impl_filepath(), 'w') as cppfile:
+            cppfile.write(impl)
diff --git a/src/pystencilssfg/emission/printers.py b/src/pystencilssfg/emission/printers.py
new file mode 100644
index 0000000000000000000000000000000000000000..9f0a03fb0557a759a68d064e2a7e0349e6703978
--- /dev/null
+++ b/src/pystencilssfg/emission/printers.py
@@ -0,0 +1,248 @@
+from __future__ import annotations
+
+from textwrap import indent
+from itertools import chain, repeat, cycle
+
+from pystencils.astnodes import KernelFunction
+from pystencils import Backend
+from pystencils.backends import generate_c
+
+from ..context import SfgContext
+from ..configuration import SfgOutputSpec
+from ..visitors import visitor
+from ..exceptions import SfgException
+
+from ..source_components import (
+    SfgEmptyLines,
+    SfgHeaderInclude,
+    SfgKernelNamespace,
+    SfgFunction,
+    SfgClass,
+    SfgConstructor,
+    SfgMemberVariable,
+    SfgMethod,
+    SfgVisibility,
+)
+
+
+def interleave(*iters):
+    try:
+        for iter in cycle(iters):
+            yield next(iter)
+    except StopIteration:
+        pass
+
+
+class SfgGeneralPrinter:
+
+    @visitor
+    def visit(self, obj: object) -> str:
+        raise SfgException(f"Can't print object of type {type(obj)}")
+
+    @visit.case(SfgEmptyLines)
+    def emptylines(self, el: SfgEmptyLines) -> str:
+        return "\n" * el.lines
+
+    @visit.case(str)
+    def string(self, s: str) -> str:
+        return s
+
+    @visit.case(SfgHeaderInclude)
+    def include(self, incl: SfgHeaderInclude) -> str:
+        if incl.system_header:
+            return f"#include <{incl.file}>"
+        else:
+            return f'#include "{incl.file}"'
+
+    def prelude(self, ctx: SfgContext) -> str:
+        if ctx.prelude_comment:
+            return "/*\n" + indent(ctx.prelude_comment, "* ", predicate=lambda _: True) + "*/\n"
+        else:
+            return ""
+
+    def param_list(self, func: SfgFunction) -> str:
+        params = sorted(list(func.parameters), key=lambda p: p.name)
+        return ", ".join(f"{param.dtype} {param.name}" for param in params)
+
+
+class SfgHeaderPrinter(SfgGeneralPrinter):
+
+    def __init__(self, ctx: SfgContext, output_spec: SfgOutputSpec):
+        self._output_spec = output_spec
+        self._ctx = ctx
+
+    def get_code(self) -> str:
+        return self.visit(self._ctx)
+
+    @visitor
+    def visit(self, obj: object) -> str:
+        return super().visit(obj)
+
+    @visit.case(SfgContext)
+    def frame(self, ctx: SfgContext) -> str:
+        code = super().prelude(ctx)
+
+        code += "\n#pragma once\n\n"
+
+        includes = filter(lambda incl: not incl.private, ctx.includes())
+        code += "\n".join(self.visit(incl) for incl in includes)
+        code += "\n\n"
+
+        fq_namespace = ctx.fully_qualified_namespace
+        if fq_namespace is not None:
+            code += f"namespace {fq_namespace} {{\n\n"
+
+        parts = interleave(
+            chain(
+                ctx.definitions(),
+                ctx.classes(),
+                ctx.functions()
+            ),
+            repeat(SfgEmptyLines(1))
+        )
+
+        code += "\n".join(self.visit(p) for p in parts)
+
+        if fq_namespace is not None:
+            code += f"}} // namespace {fq_namespace}\n"
+
+        return code
+
+    @visit.case(SfgFunction)
+    def function(self, func: SfgFunction):
+        params = sorted(list(func.parameters), key=lambda p: p.name)
+        param_list = ", ".join(f"{param.dtype} {param.name}" for param in params)
+        return f"{func.return_type} {func.name} ( {param_list} );"
+
+    @visit.case(SfgClass)
+    def sfg_class(self, cls: SfgClass):
+        code = f"{cls.class_keyword} {cls.class_name} \n"
+
+        if cls.base_classes:
+            code += f" : {','.join(cls.base_classes)}\n"
+
+        code += "{\n"
+        for visibility in (
+            SfgVisibility.DEFAULT,
+            SfgVisibility.PUBLIC,
+            SfgVisibility.PRIVATE,
+        ):
+            if visibility != SfgVisibility.DEFAULT:
+                code += f"\n{visibility}:\n"
+            for member in cls.members(visibility):
+                code += self._ctx.codestyle.indent(self.visit(member)) + "\n"
+        code += "};\n"
+
+        return code
+
+    @visit.case(SfgConstructor)
+    def sfg_constructor(self, constr: SfgConstructor):
+        code = f"{constr.owning_class.class_name} ("
+        code += ", ".join(f"{param.dtype} {param.name}" for param in constr.parameters)
+        code += ")\n"
+        if constr.initializers:
+            code += "  : " + ", ".join(constr.initializers) + "\n"
+        if constr.body:
+            code += "{\n" + self._ctx.codestyle.indent(constr.body) + "\n}\n"
+        else:
+            code += "{ }\n"
+        return code
+
+    @visit.case(SfgMemberVariable)
+    def sfg_member_var(self, var: SfgMemberVariable):
+        return f"{var.dtype} {var.name};"
+
+    @visit.case(SfgMethod)
+    def sfg_method(self, method: SfgMethod):
+        code = f"{method.return_type} {method.name} ({self.param_list(method)})"
+        code += "const" if method.const else ")"
+        if method.inline:
+            code += " {\n" + self._ctx.codestyle.indent(method.tree.get_code(self._ctx)) + "}\n"
+        else:
+            code += ";"
+        return code
+
+
+def delimiter(content):
+    return f"""\
+/*************************************************************************************
+ *                                {content}
+*************************************************************************************/
+"""
+
+
+class SfgImplPrinter(SfgGeneralPrinter):
+    def __init__(self, ctx: SfgContext, output_spec: SfgOutputSpec):
+        self._output_spec = output_spec
+        self._ctx = ctx
+
+    def get_code(self) -> str:
+        return self.visit(self._ctx)
+
+    @visitor
+    def visit(self, obj: object) -> str:
+        return super().visit(obj)
+
+    @visit.case(SfgContext)
+    def frame(self, ctx: SfgContext) -> str:
+        code = super().prelude(ctx)
+
+        code += f'\n#include "{self._output_spec.get_header_filename()}"\n\n'
+
+        includes = filter(lambda incl: incl.private, ctx.includes())
+        code += "\n".join(self.visit(incl) for incl in includes)
+
+        code += "\n\n#define FUNC_PREFIX inline\n\n"
+
+        fq_namespace = ctx.fully_qualified_namespace
+        if fq_namespace is not None:
+            code += f"namespace {fq_namespace} {{\n\n"
+
+        parts = interleave(
+            chain(
+                [delimiter("Kernels")],
+                ctx.kernel_namespaces(),
+                [delimiter("Functions")],
+                ctx.functions(),
+                [delimiter("Class Methods")],
+                ctx.classes()
+            ),
+            repeat(SfgEmptyLines(1))
+        )
+
+        code += "\n".join(self.visit(p) for p in parts)
+
+        if fq_namespace is not None:
+            code += f"}} // namespace {fq_namespace}\n"
+
+        return code
+
+    @visit.case(SfgKernelNamespace)
+    def kernel_namespace(self, kns: SfgKernelNamespace) -> str:
+        code = f"namespace {kns.name} {{\n\n"
+        code += "\n\n".join(self.visit(ast) for ast in kns.asts)
+        code += f"\n}} // namespace {kns.name}\n"
+        return code
+
+    @visit.case(KernelFunction)
+    def kernel(self, kfunc: KernelFunction) -> str:
+        return generate_c(kfunc, dialect=Backend.C)
+
+    @visit.case(SfgFunction)
+    def function(self, func: SfgFunction) -> str:
+        code = f"{func.return_type} {func.name} ({self.param_list(func)})"
+        code += "{\n" + self._ctx.codestyle.indent(func.tree.get_code(self._ctx)) + "}\n"
+        return code
+
+    @visit.case(SfgClass)
+    def sfg_class(self, cls: SfgClass) -> str:
+        methods = filter(lambda m: not m.inline, cls.methods())
+        return "\n".join(self.visit(m) for m in methods)
+
+    @visit.case(SfgMethod)
+    def sfg_method(self, method: SfgMethod) -> str:
+        const_qual = "const" if method.const else ""
+        code = f"{method.return_type} {method.owning_class.class_name}::{method.name}"
+        code += f"({self.param_list(method)}) {const_qual}"
+        code += " {\n" + self._ctx.codestyle.indent(method.tree.get_code(self._ctx)) + "}\n"
+        return code
diff --git a/src/pystencilssfg/emitters/class_declaration.py b/src/pystencilssfg/emitters/class_declaration.py
deleted file mode 100644
index f80c7ca688d7fa7cc5b98ab35f434ed07d97ea31..0000000000000000000000000000000000000000
--- a/src/pystencilssfg/emitters/class_declaration.py
+++ /dev/null
@@ -1,67 +0,0 @@
-from ..context import SfgContext
-from ..visitors import visitor
-from ..source_components import (
-    SfgClass,
-    SfgConstructor,
-    SfgMemberVariable,
-    SfgMethod,
-    SfgVisibility,
-)
-from ..exceptions import SfgException
-
-
-class ClassDeclarationPrinter:
-    def __init__(self, ctx: SfgContext):
-        self._codestyle = ctx.codestyle
-
-    def print(self, cls: SfgClass):
-        return self.visit(cls, cls)
-
-    @visitor
-    def visit(self, obj: object, cls: SfgClass) -> str:
-        raise SfgException("Can't print this.")
-
-    @visit.case(SfgClass)
-    def sfg_class(self, cls: SfgClass, _: SfgClass):
-        code = f"{cls.class_keyword} {cls.class_name} \n"
-
-        if cls.base_classes:
-            code += f" : {','.join(cls.base_classes)}\n"
-
-        code += "{\n"
-        for visibility in (
-            SfgVisibility.DEFAULT,
-            SfgVisibility.PUBLIC,
-            SfgVisibility.PRIVATE,
-        ):
-            if visibility != SfgVisibility.DEFAULT:
-                code += f"\n{visibility}:\n"
-            for member in cls.members(visibility):
-                code += self._codestyle.indent(self.visit(member, cls)) + "\n"
-        code += "};\n"
-
-        return code
-
-    @visit.case(SfgConstructor)
-    def sfg_constructor(self, constr: SfgConstructor, cls: SfgClass):
-        code = f"{cls.class_name} ("
-        code += ", ".join(f"{param.dtype} {param.name}" for param in constr.parameters)
-        code += ")\n"
-        if constr.initializers:
-            code += "  : " + ", ".join(constr.initializers) + "\n"
-        if constr.body:
-            code += "{\n" + self._codestyle.indent(constr.body) + "\n}\n"
-        else:
-            code += "{ }\n"
-        return code
-
-    @visit.case(SfgMemberVariable)
-    def sfg_member_var(self, var: SfgMemberVariable, _: SfgClass):
-        return f"{var.dtype} {var.name};"
-
-    @visit.case(SfgMethod)
-    def sfg_method(self, method: SfgMethod, _: SfgClass):
-        code = f"void {method.name} ("
-        code += ", ".join(f"{param.dtype} {param.name}" for param in method.parameters)
-        code += ");"
-        return code
diff --git a/src/pystencilssfg/emitters/header_source_pair.py b/src/pystencilssfg/emitters/header_source_pair.py
deleted file mode 100644
index c5fd1c373b1596ce4e682e23e9e181faaaebffe5..0000000000000000000000000000000000000000
--- a/src/pystencilssfg/emitters/header_source_pair.py
+++ /dev/null
@@ -1,67 +0,0 @@
-from jinja2 import Environment, PackageLoader, StrictUndefined
-
-from os import path, makedirs
-
-from ..configuration import SfgOutputSpec
-from ..context import SfgContext
-
-from .clang_format import invoke_clang_format
-
-
-class HeaderSourcePairEmitter:
-    def __init__(self, output_spec: SfgOutputSpec):
-        self._basename = output_spec.basename
-        self._output_directory = output_spec.output_directory
-        self._header_filename = output_spec.get_header_filename()
-        self._impl_filename = output_spec.get_impl_filename()
-
-        self._ospec = output_spec
-
-    @property
-    def output_files(self) -> tuple[str, str]:
-        return (
-            path.join(self._output_directory, self._header_filename),
-            path.join(self._output_directory, self._impl_filename)
-        )
-
-    def write_files(self, ctx: SfgContext):
-        fq_namespace = ctx.fully_qualified_namespace
-
-        jinja_context = {
-            'ctx': ctx,
-            'header_filename': self._header_filename,
-            'source_filename': self._impl_filename,
-            'basename': self._basename,
-            'prelude_comment': ctx.prelude_comment,
-            'definitions': tuple(ctx.definitions()),
-            'fq_namespace': fq_namespace,
-            'public_includes': tuple(incl.get_code() for incl in ctx.includes() if not incl.private),
-            'private_includes': tuple(incl.get_code() for incl in ctx.includes() if incl.private),
-            'kernel_namespaces': tuple(ctx.kernel_namespaces()),
-            'functions': tuple(ctx.functions()),
-            'classes': tuple(ctx.classes())
-        }
-
-        template_name = "HeaderSourcePair"
-
-        env = Environment(loader=PackageLoader('pystencilssfg.emitters'),
-                          undefined=StrictUndefined,
-                          trim_blocks=True,
-                          lstrip_blocks=True)
-
-        from .jinja_filters import add_filters_to_jinja
-        add_filters_to_jinja(env)
-
-        header = env.get_template(f"{template_name}.tmpl.h").render(**jinja_context)
-        source = env.get_template(f"{template_name}.tmpl.cpp").render(**jinja_context)
-
-        header = invoke_clang_format(header, ctx.codestyle)
-        source = invoke_clang_format(source, ctx.codestyle)
-
-        makedirs(self._output_directory, exist_ok=True)
-
-        with open(self._ospec.get_header_filepath(), 'w') as headerfile:
-            headerfile.write(header)
-
-        with open(self._ospec.get_impl_filepath(), 'w') as cppfile:
-            cppfile.write(source)
diff --git a/src/pystencilssfg/emitters/jinja_filters.py b/src/pystencilssfg/emitters/jinja_filters.py
deleted file mode 100644
index 67d96f018282944e28b234f3f1df5dfc7a3e726b..0000000000000000000000000000000000000000
--- a/src/pystencilssfg/emitters/jinja_filters.py
+++ /dev/null
@@ -1,48 +0,0 @@
-from jinja2 import pass_context
-from textwrap import indent
-
-from pystencils.astnodes import KernelFunction
-from pystencils import Backend
-from pystencils.backends import generate_c
-
-from pystencilssfg.source_components import SfgFunction, SfgClass
-from .class_declaration import ClassDeclarationPrinter
-
-
-def format_prelude_comment(prelude_comment: str):
-    if not prelude_comment:
-        return ""
-
-    return "/*\n" + indent(prelude_comment, "* ", predicate=lambda _: True) + "*/\n"
-
-
-@pass_context
-def generate_kernel_definition(ctx, ast: KernelFunction):
-    return generate_c(ast, dialect=Backend.C)
-
-
-@pass_context
-def generate_function_parameter_list(ctx, func: SfgFunction):
-    params = sorted(list(func.parameters), key=lambda p: p.name)
-    return ", ".join(f"{param.dtype} {param.name}" for param in params)
-
-
-@pass_context
-def generate_function_body(ctx, func: SfgFunction):
-    return func.get_code(ctx["ctx"])
-
-
-@pass_context
-def print_class_declaration(ctx, cls: SfgClass):
-    return ClassDeclarationPrinter(ctx["ctx"]).print(cls)
-
-
-def add_filters_to_jinja(jinja_env):
-    jinja_env.filters["format_prelude_comment"] = format_prelude_comment
-    jinja_env.filters["generate_kernel_definition"] = generate_kernel_definition
-    jinja_env.filters[
-        "generate_function_parameter_list"
-    ] = generate_function_parameter_list
-    jinja_env.filters["generate_function_body"] = generate_function_body
-
-    jinja_env.filters["print_class_declaration"] = print_class_declaration
diff --git a/src/pystencilssfg/emitters/templates/HeaderSourcePair.tmpl.cpp b/src/pystencilssfg/emitters/templates/HeaderSourcePair.tmpl.cpp
deleted file mode 100644
index 48c965336939f947737fb7cdbdb3889d5f14fb04..0000000000000000000000000000000000000000
--- a/src/pystencilssfg/emitters/templates/HeaderSourcePair.tmpl.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-{{ prelude_comment | format_prelude_comment }}
-
-#include "{{header_filename}}"
-
-{% for incl in private_includes %}
-{{incl}}
-{% endfor %}
-
-#define FUNC_PREFIX inline
-
-{% if fq_namespace is not none %}
-namespace {{fq_namespace}} {
-{% endif %}
-
-/*************************************************************************************
- *                                Kernels
-*************************************************************************************/
-
-{% for kns in kernel_namespaces %}
-namespace {{ kns.name }} {
-
-{% for ast in kns.asts %}
-{{ ast | generate_kernel_definition }}
-{% endfor %}
-
-} // namespace {{ kns.name }}
-{% endfor %}
-
-/*************************************************************************************
- *                                Functions
-*************************************************************************************/
-
-{% for function in functions %}
-void {{ function.name }} ( {{ function | generate_function_parameter_list }} ) { 
-  {{ function | generate_function_body | indent(ctx.codestyle.indent_width) }}
-}
-
-
-{% endfor -%}
-
-/*************************************************************************************
- *                                Class Methods
-*************************************************************************************/
-
-{% for cls in classes %}
-{% for method in cls.methods() %}
-void {{ cls.class_name }}::{{ method.name }} ( {{ method | generate_function_parameter_list }} ) { 
-  {{ method | generate_function_body | indent(ctx.codestyle.indent_width) }}
-}
-
-
-{% endfor %}
-{% endfor -%}
-
-{% if fq_namespace is not none %}
-} // namespace {{fq_namespace}}
-{% endif %}
diff --git a/src/pystencilssfg/emitters/templates/HeaderSourcePair.tmpl.h b/src/pystencilssfg/emitters/templates/HeaderSourcePair.tmpl.h
deleted file mode 100644
index 95b3ed8e207e829f48ee64a29fecc44a8c581517..0000000000000000000000000000000000000000
--- a/src/pystencilssfg/emitters/templates/HeaderSourcePair.tmpl.h
+++ /dev/null
@@ -1,31 +0,0 @@
-{{ prelude_comment | format_prelude_comment }}
-
-#pragma once
-
-#include <cstdint>
-
-{% for incl in public_includes %}
-{{incl}}
-{% endfor %}
-
-{% for definition in definitions %}
-{{ definition }}
-{% endfor %}
-
-#define RESTRICT __restrict__
-
-{% if fq_namespace is not none %}
-namespace {{fq_namespace}} {
-{% endif %}
-
-{% for cls in classes %}
-{{ cls | print_class_declaration }}
-{% endfor %}
-
-{% for function in functions %}
-void {{ function.name }} ( {{ function | generate_function_parameter_list }} );
-{% endfor %}
-
-{% if fq_namespace is not none %}
-} // namespace {{fq_namespace}}
-{% endif %}
\ No newline at end of file
diff --git a/src/pystencilssfg/generator.py b/src/pystencilssfg/generator.py
index 6a2038c289584d54585437bb1b025eebdede434a..1cd56bdc9f450a2391bacbff2e0c7bf8baef037b 100644
--- a/src/pystencilssfg/generator.py
+++ b/src/pystencilssfg/generator.py
@@ -26,7 +26,7 @@ class SourceFileGenerator:
 
         self._context = SfgContext(config.outer_namespace, config.codestyle, argv=script_args)
 
-        from .emitters import HeaderSourcePairEmitter
+        from .emission import HeaderSourcePairEmitter
         self._emitter = HeaderSourcePairEmitter(config.get_output_spec(basename))
 
     def clean_files(self):
diff --git a/src/pystencilssfg/source_components.py b/src/pystencilssfg/source_components.py
index d0bf5c2c0a5a7af72cbf05e576ba6755b17001fc..1bf7242ce6ca8099d04706d058e3c97ac30b3ace 100644
--- a/src/pystencilssfg/source_components.py
+++ b/src/pystencilssfg/source_components.py
@@ -13,10 +13,18 @@ from .source_concepts import SrcObject
 from .exceptions import SfgException
 
 if TYPE_CHECKING:
-    from .context import SfgContext
     from .tree import SfgCallTreeNode
 
 
+class SfgEmptyLines:
+    def __init__(self, lines: int):
+        self._lines = lines
+
+    @property
+    def lines(self) -> int:
+        return self._lines
+
+
 class SfgHeaderInclude:
     def __init__(
         self, header_file: str, system_header: bool = False, private: bool = False
@@ -25,6 +33,10 @@ class SfgHeaderInclude:
         self._system_header = system_header
         self._private = private
 
+    @property
+    def file(self) -> str:
+        return self._header_file
+
     @property
     def system_header(self):
         return self._system_header
@@ -33,12 +45,6 @@ class SfgHeaderInclude:
     def private(self):
         return self._private
 
-    def get_code(self):
-        if self._system_header:
-            return f"#include <{self._header_file}>"
-        else:
-            return f'#include "{self._header_file}"'
-
     def __hash__(self) -> int:
         return hash((self._header_file, self._system_header, self._private))
 
@@ -166,9 +172,10 @@ class SfgKernelHandle:
 
 
 class SfgFunction:
-    def __init__(self, name: str, tree: SfgCallTreeNode):
+    def __init__(self, name: str, tree: SfgCallTreeNode, return_type: SrcType = SrcType("void")):
         self._name = name
         self._tree = tree
+        self._return_type = return_type
 
         from .visitors.tree_visitors import ExpandingParameterCollector
 
@@ -187,8 +194,9 @@ class SfgFunction:
     def tree(self):
         return self._tree
 
-    def get_code(self, ctx: SfgContext):
-        return self._tree.get_code(ctx)
+    @property
+    def return_type(self) -> SrcType:
+        return self._return_type
 
 
 class SfgVisibility(Enum):
@@ -219,9 +227,14 @@ class SfgClassKeyword(Enum):
 
 
 class SfgClassMember(ABC):
-    def __init__(self, visibility: SfgVisibility):
+    def __init__(self, cls: SfgClass, visibility: SfgVisibility):
+        self._cls = cls
         self._visibility = visibility
 
+    @property
+    def owning_class(self) -> SfgClass:
+        return self._cls
+
     @property
     def visibility(self) -> SfgVisibility:
         return self._visibility
@@ -232,10 +245,11 @@ class SfgMemberVariable(SrcObject, SfgClassMember):
         self,
         name: str,
         type: SrcType,
+        cls: SfgClass,
         visibility: SfgVisibility = SfgVisibility.PRIVATE,
     ):
         SrcObject.__init__(self, type, name)
-        SfgClassMember.__init__(self, visibility)
+        SfgClassMember.__init__(self, cls, visibility)
 
 
 class SfgMethod(SfgFunction, SfgClassMember):
@@ -243,21 +257,37 @@ class SfgMethod(SfgFunction, SfgClassMember):
         self,
         name: str,
         tree: SfgCallTreeNode,
+        cls: SfgClass,
         visibility: SfgVisibility = SfgVisibility.PUBLIC,
+        return_type: SrcType = SrcType("void"),
+        inline: bool = False,
+        const: bool = False
     ):
-        SfgFunction.__init__(self, name, tree)
-        SfgClassMember.__init__(self, visibility)
+        SfgFunction.__init__(self, name, tree, return_type=return_type)
+        SfgClassMember.__init__(self, cls, visibility)
+
+        self._inline = inline
+        self._const = const
+
+    @property
+    def inline(self) -> bool:
+        return self._inline
+
+    @property
+    def const(self) -> bool:
+        return self._const
 
 
 class SfgConstructor(SfgClassMember):
     def __init__(
         self,
+        cls: SfgClass,
         parameters: Sequence[SrcObject] = (),
         initializers: Sequence[str] = (),
         body: str = "",
         visibility: SfgVisibility = SfgVisibility.PUBLIC,
     ):
-        SfgClassMember.__init__(self, visibility)
+        SfgClassMember.__init__(self, cls, visibility)
         self._parameters = tuple(parameters)
         self._initializers = tuple(initializers)
         self._body = body