Coverage for src/pystencilssfg/ir/syntax.py: 94%
112 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-04 07:16 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-04 07:16 +0000
1from __future__ import annotations
3from enum import Enum, auto
4from typing import (
5 Iterable,
6 TypeVar,
7 Generic,
8)
10from ..lang import HeaderFile
12from .entities import (
13 SfgNamespace,
14 SfgKernelHandle,
15 SfgFunction,
16 SfgClassMember,
17 SfgVisibility,
18 SfgClass,
19)
21# =========================================================================================================
22#
23# SYNTACTICAL ELEMENTS
24#
25# These classes model *code elements*, which represent the actual syntax objects that populate the output
26# files, their namespaces and class bodies.
27#
28# =========================================================================================================
31SourceEntity_T = TypeVar(
32 "SourceEntity_T",
33 bound=SfgKernelHandle | SfgFunction | SfgClassMember | SfgClass,
34 covariant=True,
35)
36"""Source entities that may have declarations and definitions."""
39class SfgEntityDecl(Generic[SourceEntity_T]):
40 """Declaration of a function, class, method, or constructor"""
42 __match_args__ = ("entity",)
44 def __init__(self, entity: SourceEntity_T) -> None:
45 self._entity = entity
47 @property
48 def entity(self) -> SourceEntity_T:
49 return self._entity
52class SfgEntityDef(Generic[SourceEntity_T]):
53 """Definition of a function, class, method, or constructor"""
55 __match_args__ = ("entity",)
57 def __init__(self, entity: SourceEntity_T) -> None:
58 self._entity = entity
60 @property
61 def entity(self) -> SourceEntity_T:
62 return self._entity
65SfgClassBodyElement = str | SfgEntityDecl[SfgClassMember] | SfgEntityDef[SfgClassMember]
66"""Elements that may be placed in the visibility blocks of a class body."""
69class SfgVisibilityBlock:
70 """Visibility-qualified block inside a class definition body.
72 Visibility blocks host the code elements placed inside a class body:
73 method and constructor declarations,
74 in-class method and constructor definitions,
75 as well as variable declarations and definitions.
77 Args:
78 visibility: The visibility qualifier of this block
79 """
81 __match_args__ = ("visibility", "elements")
83 def __init__(self, visibility: SfgVisibility) -> None:
84 self._vis = visibility
85 self._elements: list[SfgClassBodyElement] = []
86 self._cls: SfgClass | None = None
88 @property
89 def visibility(self) -> SfgVisibility:
90 return self._vis
92 @property
93 def elements(self) -> list[SfgClassBodyElement]:
94 return self._elements
96 @elements.setter
97 def elements(self, elems: Iterable[SfgClassBodyElement]):
98 self._elements = list(elems)
101class SfgNamespaceBlock:
102 """A C++ namespace block.
104 Args:
105 namespace: Namespace associated with this block
106 label: Label printed at the opening brace of this block.
107 This may be the namespace name, or a compressed qualified
108 name containing one or more of its parent namespaces.
109 """
111 __match_args__ = (
112 "namespace",
113 "elements",
114 "label",
115 )
117 def __init__(self, namespace: SfgNamespace, label: str | None = None) -> None:
118 self._namespace = namespace
119 self._label = label if label is not None else namespace.name
120 self._elements: list[SfgNamespaceElement] = []
122 @property
123 def namespace(self) -> SfgNamespace:
124 return self._namespace
126 @property
127 def label(self) -> str:
128 return self._label
130 @property
131 def elements(self) -> list[SfgNamespaceElement]:
132 """Sequence of source elements that make up the body of this namespace"""
133 return self._elements
135 @elements.setter
136 def elements(self, elems: Iterable[SfgNamespaceElement]):
137 self._elements = list(elems)
140class SfgClassBody:
141 """Body of a class definition."""
143 __match_args__ = ("associated_class", "visibility_blocks")
145 def __init__(
146 self,
147 cls: SfgClass,
148 default_block: SfgVisibilityBlock,
149 vis_blocks: Iterable[SfgVisibilityBlock],
150 ) -> None:
151 self._cls = cls
152 assert default_block.visibility == SfgVisibility.DEFAULT
153 self._default_block = default_block
154 self._blocks = [self._default_block] + list(vis_blocks)
156 @property
157 def associated_class(self) -> SfgClass:
158 return self._cls
160 @property
161 def default(self) -> SfgVisibilityBlock:
162 return self._default_block
164 def append_visibility_block(self, block: SfgVisibilityBlock):
165 if block.visibility == SfgVisibility.DEFAULT:
166 raise ValueError(
167 "Can't add another block with DEFAULT visibility to this class body."
168 )
169 self._blocks.append(block)
171 @property
172 def visibility_blocks(self) -> tuple[SfgVisibilityBlock, ...]:
173 return tuple(self._blocks)
176SfgNamespaceElement = (
177 str | SfgNamespaceBlock | SfgClassBody | SfgEntityDecl | SfgEntityDef
178)
179"""Elements that may be placed inside a namespace, including the global namespace."""
182class SfgSourceFileType(Enum):
183 HEADER = auto()
184 TRANSLATION_UNIT = auto()
187class SfgSourceFile:
188 """A C++ source file.
190 Args:
191 name: Name of the file (without parent directories), e.g. ``Algorithms.cpp``
192 file_type: Type of the source file (header or translation unit)
193 prelude: Optionally, text of the prelude comment printed at the top of the file
194 """
196 def __init__(
197 self, name: str, file_type: SfgSourceFileType, prelude: str | None = None
198 ) -> None:
199 self._name: str = name
200 self._file_type: SfgSourceFileType = file_type
201 self._prelude: str | None = prelude
202 self._includes: list[HeaderFile] = []
203 self._elements: list[SfgNamespaceElement] = []
205 @property
206 def name(self) -> str:
207 """Name of this source file"""
208 return self._name
210 @property
211 def file_type(self) -> SfgSourceFileType:
212 """File type of this source file"""
213 return self._file_type
215 @property
216 def prelude(self) -> str | None:
217 """Text of the prelude comment"""
218 return self._prelude
220 @prelude.setter
221 def prelude(self, text: str | None):
222 self._prelude = text
224 @property
225 def includes(self) -> list[HeaderFile]:
226 """Sequence of header files to be included at the top of this file"""
227 return self._includes
229 @includes.setter
230 def includes(self, incl: Iterable[HeaderFile]):
231 self._includes = list(incl)
233 @property
234 def elements(self) -> list[SfgNamespaceElement]:
235 """Sequence of source elements comprising the body of this file"""
236 return self._elements
238 @elements.setter
239 def elements(self, elems: Iterable[SfgNamespaceElement]):
240 self._elements = list(elems)