diff --git a/aas_core_codegen/csharp/description.py b/aas_core_codegen/csharp/description.py index 65f7847d9..2a81dcd88 100644 --- a/aas_core_codegen/csharp/description.py +++ b/aas_core_codegen/csharp/description.py @@ -36,7 +36,6 @@ ) from aas_core_codegen.intermediate import ( doc as intermediate_doc, - rendering as intermediate_rendering, _translate as intermediate_translate, ) @@ -153,7 +152,7 @@ def visit_element(self, node: _Element) -> None: self.visit(node.children) -class _ElementRenderer(intermediate_rendering.DocutilsElementTransformer[_NodeUnion]): +class _ElementRenderer(intermediate_doc.DocutilsElementTransformer[_NodeUnion]): """Render descriptions as C# docstring XML.""" def transform_text( diff --git a/aas_core_codegen/golang/description.py b/aas_core_codegen/golang/description.py index 7c26c9910..12d5a8144 100644 --- a/aas_core_codegen/golang/description.py +++ b/aas_core_codegen/golang/description.py @@ -26,7 +26,6 @@ ) from aas_core_codegen.intermediate import ( doc as intermediate_doc, - rendering as intermediate_rendering, ) @@ -56,7 +55,7 @@ def __init__( self.cls_or_enum = cls_or_enum -class _ElementRenderer(intermediate_rendering.DocutilsElementTransformer[str]): +class _ElementRenderer(intermediate_doc.DocutilsElementTransformer[str]): """Render descriptions as a content of a docstring.""" def __init__(self, context: Context) -> None: diff --git a/aas_core_codegen/intermediate/_translate.py b/aas_core_codegen/intermediate/_translate.py index a42cffc27..3c6dae117 100644 --- a/aas_core_codegen/intermediate/_translate.py +++ b/aas_core_codegen/intermediate/_translate.py @@ -40,7 +40,6 @@ construction, doc, pattern_verification, - rendering, ) from aas_core_codegen.intermediate._types import ( SymbolTable, @@ -4195,7 +4194,7 @@ def check_and_report_duplicate( def _verify_description_rendering_with_smoke(symbol_table: SymbolTable) -> List[Error]: """Check that we can smoke-render all the descriptions.""" - class DummyRenderer(rendering.DocutilsElementTransformer[bool]): + class DummyRenderer(doc.DocutilsElementTransformer[bool]): """Perform a smoke rendering to test that all the elements have been covered.""" def transform_text( diff --git a/aas_core_codegen/intermediate/doc.py b/aas_core_codegen/intermediate/doc.py index 7e981bb46..443ff4fdf 100644 --- a/aas_core_codegen/intermediate/doc.py +++ b/aas_core_codegen/intermediate/doc.py @@ -1,12 +1,12 @@ """Provide types for the references in the docstrings.""" # pylint: disable=keyword-arg-before-vararg - -from typing import Union +import abc +from typing import Union, Tuple, Optional, TypeVar, Generic, List import docutils import docutils.nodes -from icontract import require +from icontract import require, ensure, DBC from aas_core_codegen.intermediate._types import ( OurType, @@ -143,3 +143,202 @@ def __init__( # type: ignore docutils.nodes.TextElement.__init__( self, rawsource, text, *children, **attributes ) + + +T = TypeVar("T") + + +class DocutilsElementTransformer(Generic[T], DBC): + """ + Transform a pre-defined subset of the docutils elements. + + The subset is limited to the elements which we expect in the docstrings of + our meta-model. Following YAGNI ("you ain't gonna need it"), we do not visit + all the possible elements as our docstrings are indeed limited in style. + + Following a common pattern throughout this code base, all the transforming functions + return either a result or an error. + """ + + @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) + def transform( + self, element: docutils.nodes.Element + ) -> Tuple[Optional[T], Optional[List[str]]]: + """Dispatch the transformation to the appropriate ``transform_*``.""" + # NOTE (mristin, 2021-12-26): + # Please keep the dispatching order. We have to implement a chain-of-command, + # not an efficient dispatch as classes inherit from each other. + + if isinstance(element, docutils.nodes.Text): + return self.transform_text(element) + + elif isinstance(element, ReferenceToOurType): + return self.transform_reference_to_our_type_in_doc(element) + + elif isinstance(element, ReferenceToAttribute): + return self.transform_reference_to_attribute_in_doc(element) + + elif isinstance(element, ReferenceToArgument): + return self.transform_reference_to_argument_in_doc(element) + + elif isinstance(element, ReferenceToConstraint): + return self.transform_reference_to_constraint_in_doc(element) + + elif isinstance(element, ReferenceToConstant): + return self.transform_reference_to_constant_in_doc(element) + + elif isinstance(element, docutils.nodes.literal): + return self.transform_literal(element) + + elif isinstance(element, docutils.nodes.paragraph): + return self.transform_paragraph(element) + + elif isinstance(element, docutils.nodes.emphasis): + return self.transform_emphasis(element) + + elif isinstance(element, docutils.nodes.list_item): + return self.transform_list_item(element) + + elif isinstance(element, docutils.nodes.bullet_list): + return self.transform_bullet_list(element) + + elif isinstance(element, docutils.nodes.note): + return self.transform_note(element) + + elif isinstance(element, docutils.nodes.reference): + return self.transform_reference(element) + + elif isinstance(element, docutils.nodes.field_body): + return self.transform_field_body(element) + + elif isinstance(element, docutils.nodes.document): + return self.transform_document(element) + + else: + return None, [ + ( + f"Handling of the element of a description " + f"with type {type(element)} " + f"has not been implemented: {element}" + ) + ] + + @abc.abstractmethod + @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) + def transform_text( + self, element: docutils.nodes.Text + ) -> Tuple[Optional[T], Optional[List[str]]]: + """Transform a text element into something.""" + raise NotImplementedError() + + @abc.abstractmethod + @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) + def transform_reference_to_our_type_in_doc( + self, element: ReferenceToOurType + ) -> Tuple[Optional[T], Optional[List[str]]]: + """Transform a reference to our type into something.""" + raise NotImplementedError() + + @abc.abstractmethod + @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) + def transform_reference_to_attribute_in_doc( + self, element: ReferenceToAttribute + ) -> Tuple[Optional[T], Optional[List[str]]]: + """Transform a reference to an attribute into something.""" + raise NotImplementedError() + + @abc.abstractmethod + @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) + def transform_reference_to_argument_in_doc( + self, element: ReferenceToArgument + ) -> Tuple[Optional[T], Optional[List[str]]]: + """Transform a reference to an argument into something.""" + raise NotImplementedError() + + @abc.abstractmethod + @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) + def transform_reference_to_constraint_in_doc( + self, element: ReferenceToConstraint + ) -> Tuple[Optional[T], Optional[List[str]]]: + """Transform a reference to a constraint into something.""" + raise NotImplementedError() + + @abc.abstractmethod + @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) + def transform_reference_to_constant_in_doc( + self, element: ReferenceToConstant + ) -> Tuple[Optional[T], Optional[List[str]]]: + """Transform a reference to a constant into something.""" + raise NotImplementedError() + + @abc.abstractmethod + @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) + def transform_literal( + self, element: docutils.nodes.literal + ) -> Tuple[Optional[T], Optional[List[str]]]: + """Transform a code literal into something.""" + raise NotImplementedError() + + @abc.abstractmethod + @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) + def transform_paragraph( + self, element: docutils.nodes.paragraph + ) -> Tuple[Optional[T], Optional[List[str]]]: + """Transform a paragraph element into something.""" + raise NotImplementedError() + + @abc.abstractmethod + @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) + def transform_emphasis( + self, element: docutils.nodes.emphasis + ) -> Tuple[Optional[T], Optional[List[str]]]: + """Transform an emphasis element into something.""" + raise NotImplementedError() + + @abc.abstractmethod + @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) + def transform_list_item( + self, element: docutils.nodes.list_item + ) -> Tuple[Optional[T], Optional[List[str]]]: + """Transform a list item element into something.""" + raise NotImplementedError() + + @abc.abstractmethod + @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) + def transform_bullet_list( + self, element: docutils.nodes.bullet_list + ) -> Tuple[Optional[T], Optional[List[str]]]: + """Transform a bullet list element into something.""" + raise NotImplementedError() + + @abc.abstractmethod + @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) + def transform_note( + self, element: docutils.nodes.note + ) -> Tuple[Optional[T], Optional[List[str]]]: + """Transform a note element into something.""" + raise NotImplementedError() + + @abc.abstractmethod + @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) + def transform_reference( + self, element: docutils.nodes.reference + ) -> Tuple[Optional[T], Optional[List[str]]]: + """Transform a general reference element into something.""" + raise NotImplementedError() + + @abc.abstractmethod + @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) + def transform_field_body( + self, element: docutils.nodes.field_body + ) -> Tuple[Optional[T], Optional[List[str]]]: + """Transform a field body into something.""" + raise NotImplementedError() + + @abc.abstractmethod + @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) + def transform_document( + self, element: docutils.nodes.document + ) -> Tuple[Optional[T], Optional[List[str]]]: + """Transform a document into something.""" + raise NotImplementedError() diff --git a/aas_core_codegen/intermediate/rendering.py b/aas_core_codegen/intermediate/rendering.py deleted file mode 100644 index 860bab2cf..000000000 --- a/aas_core_codegen/intermediate/rendering.py +++ /dev/null @@ -1,206 +0,0 @@ -"""Provide rendering functions for common generation tasks.""" -import abc -from typing import TypeVar, Generic, Tuple, Optional, List - -import docutils.nodes -from icontract import ensure, DBC - -from aas_core_codegen.intermediate import doc - -T = TypeVar("T") - - -class DocutilsElementTransformer(Generic[T], DBC): - """ - Transform a pre-defined subset of the docutils elements. - - The subset is limited to the elements which we expect in the docstrings of - our meta-model. Following YAGNI ("you ain't gonna need it"), we do not visit - all the possible elements as our docstrings are indeed limited in style. - - Following a common pattern throughout this code base, all the transforming functions - return either a result or an error. - """ - - @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) - def transform( - self, element: docutils.nodes.Element - ) -> Tuple[Optional[T], Optional[List[str]]]: - """Dispatch the transformation to the appropriate ``transform_*``.""" - # NOTE (mristin, 2021-12-26): - # Please keep the dispatching order. We have to implement a chain-of-command, - # not an efficient dispatch as classes inherit from each other. - - if isinstance(element, docutils.nodes.Text): - return self.transform_text(element) - - elif isinstance(element, doc.ReferenceToOurType): - return self.transform_reference_to_our_type_in_doc(element) - - elif isinstance(element, doc.ReferenceToAttribute): - return self.transform_reference_to_attribute_in_doc(element) - - elif isinstance(element, doc.ReferenceToArgument): - return self.transform_reference_to_argument_in_doc(element) - - elif isinstance(element, doc.ReferenceToConstraint): - return self.transform_reference_to_constraint_in_doc(element) - - elif isinstance(element, doc.ReferenceToConstant): - return self.transform_reference_to_constant_in_doc(element) - - elif isinstance(element, docutils.nodes.literal): - return self.transform_literal(element) - - elif isinstance(element, docutils.nodes.paragraph): - return self.transform_paragraph(element) - - elif isinstance(element, docutils.nodes.emphasis): - return self.transform_emphasis(element) - - elif isinstance(element, docutils.nodes.list_item): - return self.transform_list_item(element) - - elif isinstance(element, docutils.nodes.bullet_list): - return self.transform_bullet_list(element) - - elif isinstance(element, docutils.nodes.note): - return self.transform_note(element) - - elif isinstance(element, docutils.nodes.reference): - return self.transform_reference(element) - - elif isinstance(element, docutils.nodes.field_body): - return self.transform_field_body(element) - - elif isinstance(element, docutils.nodes.document): - return self.transform_document(element) - - else: - return None, [ - ( - f"Handling of the element of a description " - f"with type {type(element)} " - f"has not been implemented: {element}" - ) - ] - - @abc.abstractmethod - @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) - def transform_text( - self, element: docutils.nodes.Text - ) -> Tuple[Optional[T], Optional[List[str]]]: - """Transform a text element into something.""" - raise NotImplementedError() - - @abc.abstractmethod - @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) - def transform_reference_to_our_type_in_doc( - self, element: doc.ReferenceToOurType - ) -> Tuple[Optional[T], Optional[List[str]]]: - """Transform a reference to our type into something.""" - raise NotImplementedError() - - @abc.abstractmethod - @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) - def transform_reference_to_attribute_in_doc( - self, element: doc.ReferenceToAttribute - ) -> Tuple[Optional[T], Optional[List[str]]]: - """Transform a reference to an attribute into something.""" - raise NotImplementedError() - - @abc.abstractmethod - @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) - def transform_reference_to_argument_in_doc( - self, element: doc.ReferenceToArgument - ) -> Tuple[Optional[T], Optional[List[str]]]: - """Transform a reference to an argument into something.""" - raise NotImplementedError() - - @abc.abstractmethod - @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) - def transform_reference_to_constraint_in_doc( - self, element: doc.ReferenceToConstraint - ) -> Tuple[Optional[T], Optional[List[str]]]: - """Transform a reference to a constraint into something.""" - raise NotImplementedError() - - @abc.abstractmethod - @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) - def transform_reference_to_constant_in_doc( - self, element: doc.ReferenceToConstant - ) -> Tuple[Optional[T], Optional[List[str]]]: - """Transform a reference to a constant into something.""" - raise NotImplementedError() - - @abc.abstractmethod - @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) - def transform_literal( - self, element: docutils.nodes.literal - ) -> Tuple[Optional[T], Optional[List[str]]]: - """Transform a code literal into something.""" - raise NotImplementedError() - - @abc.abstractmethod - @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) - def transform_paragraph( - self, element: docutils.nodes.paragraph - ) -> Tuple[Optional[T], Optional[List[str]]]: - """Transform a paragraph element into something.""" - raise NotImplementedError() - - @abc.abstractmethod - @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) - def transform_emphasis( - self, element: docutils.nodes.emphasis - ) -> Tuple[Optional[T], Optional[List[str]]]: - """Transform an emphasis element into something.""" - raise NotImplementedError() - - @abc.abstractmethod - @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) - def transform_list_item( - self, element: docutils.nodes.list_item - ) -> Tuple[Optional[T], Optional[List[str]]]: - """Transform a list item element into something.""" - raise NotImplementedError() - - @abc.abstractmethod - @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) - def transform_bullet_list( - self, element: docutils.nodes.bullet_list - ) -> Tuple[Optional[T], Optional[List[str]]]: - """Transform a bullet list element into something.""" - raise NotImplementedError() - - @abc.abstractmethod - @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) - def transform_note( - self, element: docutils.nodes.note - ) -> Tuple[Optional[T], Optional[List[str]]]: - """Transform a note element into something.""" - raise NotImplementedError() - - @abc.abstractmethod - @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) - def transform_reference( - self, element: docutils.nodes.reference - ) -> Tuple[Optional[T], Optional[List[str]]]: - """Transform a general reference element into something.""" - raise NotImplementedError() - - @abc.abstractmethod - @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) - def transform_field_body( - self, element: docutils.nodes.field_body - ) -> Tuple[Optional[T], Optional[List[str]]]: - """Transform a field body into something.""" - raise NotImplementedError() - - @abc.abstractmethod - @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) - def transform_document( - self, element: docutils.nodes.document - ) -> Tuple[Optional[T], Optional[List[str]]]: - """Transform a document into something.""" - raise NotImplementedError() diff --git a/aas_core_codegen/python/description.py b/aas_core_codegen/python/description.py index 0cdafbc31..2341e95da 100644 --- a/aas_core_codegen/python/description.py +++ b/aas_core_codegen/python/description.py @@ -23,7 +23,6 @@ ) from aas_core_codegen.intermediate import ( doc as intermediate_doc, - rendering as intermediate_rendering, ) from aas_core_codegen.python import ( common as python_common, @@ -62,7 +61,7 @@ def __init__( self.cls_or_enum = cls_or_enum -class _ElementRenderer(intermediate_rendering.DocutilsElementTransformer[str]): +class _ElementRenderer(intermediate_doc.DocutilsElementTransformer[str]): """Render descriptions as a content of a docstring.""" def __init__(self, context: Context) -> None: diff --git a/aas_core_codegen/rdf_shacl/_description.py b/aas_core_codegen/rdf_shacl/_description.py index 54c6bab5d..5eeecb5a0 100644 --- a/aas_core_codegen/rdf_shacl/_description.py +++ b/aas_core_codegen/rdf_shacl/_description.py @@ -7,7 +7,6 @@ from aas_core_codegen.common import assert_never, assert_union_of_descendants_exhaustive from aas_core_codegen.intermediate import ( doc as intermediate_doc, - rendering as intermediate_rendering, ) from aas_core_codegen.rdf_shacl import naming as rdf_shacl_naming @@ -103,7 +102,7 @@ def without_redundant_breaks(tokens: Sequence["TokenUnion"]) -> List["TokenUnion return result -class Renderer(intermediate_rendering.DocutilsElementTransformer[List["TokenUnion"]]): +class Renderer(intermediate_doc.DocutilsElementTransformer[List["TokenUnion"]]): """Render descriptions as C# docstring XML.""" # fmt: off diff --git a/aas_core_codegen/typescript/description.py b/aas_core_codegen/typescript/description.py index d3f06a6e4..83035e659 100644 --- a/aas_core_codegen/typescript/description.py +++ b/aas_core_codegen/typescript/description.py @@ -22,7 +22,6 @@ ) from aas_core_codegen.intermediate import ( doc as intermediate_doc, - rendering as intermediate_rendering, ) from aas_core_codegen.typescript import ( common as typescript_common, @@ -55,7 +54,7 @@ def __init__( self.cls_or_enum = cls_or_enum -class _ElementRenderer(intermediate_rendering.DocutilsElementTransformer[str]): +class _ElementRenderer(intermediate_doc.DocutilsElementTransformer[str]): """Render descriptions as a content of a docstring.""" def __init__(self, context: Context) -> None: