Source code for elliptic.Kernel.Expression

from contextlib import contextmanager

from anytree import NodeMixin
from typing import Iterable, Iterator, Type

from .Context import ContextDelegate, Context


[docs]class EllipticNode(NodeMixin): """Base class for representing a node in the DSL tree. """ last_id: int = 0 def __init__(self) -> None: super().__init__() self.children: Iterable = tuple() self.name: str = '' self.unique_id = EllipticNode.last_id EllipticNode.last_id += 1 self.shape = "shape=box" def _name_func(self) -> str: return str(self.unique_id) + '\n' + self.name def _shape(self) -> str: return self.shape
[docs] def export_tree(self, filename: str) -> None: """Exports a graphical representation of the DSL tree. This method can be called from any tree node. The tree root will always be used. Parameters: filename: Name for the exported image file. """ from anytree.exporter import DotExporter exporter = DotExporter(self.root, nodenamefunc=lambda node: node._name_func(), nodeattrfunc=lambda node: node._shape()) exporter.to_picture(filename)
[docs]class Expression(EllipticNode): """Base class for building DSL expressions. Parameters: context_delegate: A context delegate object responsible for generating some Cython code. display_name: The name that will be displayed when this Expression is rendered into a picture. display_args: The arguments that will be displayed below this Expression name in the rendered picture. """ def __init__(self, context_delegate: Type[ContextDelegate], display_name="", display_args=None) -> None: super().__init__() if not display_args: display_args = {} args_str = "" for k, v in display_args.items(): args_str = f"{args_str}\n{k}={v}" self.name = f"{display_name}{args_str}" self.context_delegate = context_delegate def add_child(self, expr: 'Expression'): self.children += (expr,)
[docs] def render(self, template_manager, child: str, context_delegate: ContextDelegate) -> str: """Render the expression generated code. Parameters: template_manager: A `TemplateManagerBase` instance. child: The rendered template corresponding to this node's child. context_delegate: The context delegate for the DSL. """ template_file = context_delegate.get_template_file() template = template_manager.get_template(template_file) kwargs = context_delegate.template_kwargs() rendered_template = template.render(child=child, **kwargs) return rendered_template
[docs] @contextmanager def visit(self, context: Context) -> Iterator[ContextDelegate]: """Context manager used when an expression node is visited in the DSL tree. Calls the :class:`context delegate <elliptic.Kernel.Context.ContextDelegate>` :meth:`~elliptic.Kernel.Context.ContextDelegate.context_enter` and :meth:`~elliptic.Kernel.Context.ContextDelegate.context_exit` methods. Parameters: context: A context object. """ context_delegate = self.context_delegate(context, self.unique_id) # ContextDelegate does not implement a context manager so that it can be a simpler protocol context_delegate.context_enter() yield context_delegate context_delegate.context_exit()