fprime-cpp-codegen 0.1.0__py3-none-any.whl → 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fprime_cpp_codegen/__init__.py +8 -0
- fprime_cpp_codegen/body.py +16 -8
- fprime_cpp_codegen/builder/coercion.py +11 -0
- fprime_cpp_codegen/builder/decoration.py +3 -2
- fprime_cpp_codegen/builder/definitions.py +31 -9
- fprime_cpp_codegen/builder/document.py +93 -8
- fprime_cpp_codegen/builder/scopes.py +307 -61
- fprime_cpp_codegen/comments.py +77 -14
- fprime_cpp_codegen/doc.py +43 -8
- fprime_cpp_codegen/lines.py +12 -2
- fprime_cpp_codegen/output.py +48 -16
- fprime_cpp_codegen/validation.py +256 -0
- fprime_cpp_codegen/writer.py +64 -16
- {fprime_cpp_codegen-0.1.0.dist-info → fprime_cpp_codegen-0.2.0.dist-info}/METADATA +73 -1
- fprime_cpp_codegen-0.2.0.dist-info/RECORD +24 -0
- fprime_cpp_codegen-0.1.0.dist-info/RECORD +0 -23
- {fprime_cpp_codegen-0.1.0.dist-info → fprime_cpp_codegen-0.2.0.dist-info}/WHEEL +0 -0
- {fprime_cpp_codegen-0.1.0.dist-info → fprime_cpp_codegen-0.2.0.dist-info}/licenses/LICENSE +0 -0
- {fprime_cpp_codegen-0.1.0.dist-info → fprime_cpp_codegen-0.2.0.dist-info}/top_level.txt +0 -0
fprime_cpp_codegen/__init__.py
CHANGED
|
@@ -10,6 +10,7 @@ The package is layered, and you can enter at whichever level suits the job:
|
|
|
10
10
|
* :mod:`~fprime_cpp_codegen.comments` -- comment and banner formatting.
|
|
11
11
|
* :mod:`~fprime_cpp_codegen.lines` -- the line model everything is built on.
|
|
12
12
|
* :mod:`~fprime_cpp_codegen.output` -- rendering to text and to disk.
|
|
13
|
+
* :mod:`~fprime_cpp_codegen.validation` -- whole-document checks.
|
|
13
14
|
* :mod:`~fprime_cpp_codegen.formatting` -- optional post-processing through
|
|
14
15
|
``clang-format``.
|
|
15
16
|
* :mod:`~fprime_cpp_codegen.fprime` -- F Prime conventions. Import it explicitly;
|
|
@@ -52,6 +53,7 @@ from .doc import (
|
|
|
52
53
|
VOID,
|
|
53
54
|
Class,
|
|
54
55
|
ClassMember,
|
|
56
|
+
Comment,
|
|
55
57
|
Constructor,
|
|
56
58
|
CppDoc,
|
|
57
59
|
DefaultFileBanner,
|
|
@@ -83,6 +85,7 @@ from .lines import (
|
|
|
83
85
|
wrap_in_scope,
|
|
84
86
|
)
|
|
85
87
|
from .output import WriteResult, collect_cpp_files, doc_files, write_doc
|
|
88
|
+
from .validation import check_document, orphaned_members, unfilled_definitions
|
|
86
89
|
from .writer import (
|
|
87
90
|
Context,
|
|
88
91
|
CppWriter,
|
|
@@ -108,6 +111,7 @@ __all__ = [
|
|
|
108
111
|
"VOID",
|
|
109
112
|
"Class",
|
|
110
113
|
"ClassMember",
|
|
114
|
+
"Comment",
|
|
111
115
|
"Constructor",
|
|
112
116
|
"CppDoc",
|
|
113
117
|
"DefaultFileBanner",
|
|
@@ -155,6 +159,10 @@ __all__ = [
|
|
|
155
159
|
"collect_cpp_files",
|
|
156
160
|
"doc_files",
|
|
157
161
|
"write_doc",
|
|
162
|
+
# Validation
|
|
163
|
+
"check_document",
|
|
164
|
+
"orphaned_members",
|
|
165
|
+
"unfilled_definitions",
|
|
158
166
|
# Errors
|
|
159
167
|
"CppCodegenError",
|
|
160
168
|
"ScopeError",
|
fprime_cpp_codegen/body.py
CHANGED
|
@@ -34,6 +34,7 @@ from .comments import (
|
|
|
34
34
|
write_comment_body,
|
|
35
35
|
write_doxygen_comment,
|
|
36
36
|
)
|
|
37
|
+
from .doc import Comment
|
|
37
38
|
from .errors import ScopeError, ValidationError
|
|
38
39
|
from .lines import Line, blank, indent_lines
|
|
39
40
|
from .lines import line as _line
|
|
@@ -44,7 +45,9 @@ __all__ = ["Body", "Code", "Switch", "stmts"]
|
|
|
44
45
|
|
|
45
46
|
#: Anything usable as a run of C++ statements. ``None`` contributes nothing, so
|
|
46
47
|
#: ``b.add(frag if condition else None)`` needs no branch. A ``str`` is
|
|
47
|
-
#: margin-stripped and taken verbatim, with no punctuation added
|
|
48
|
+
#: margin-stripped and taken verbatim, with no punctuation added; pass a
|
|
49
|
+
#: :class:`~fprime_cpp_codegen.lines.Line` instead, or use :meth:`Body.line`, for text
|
|
50
|
+
#: that must survive a leading ``|``.
|
|
48
51
|
Code: TypeAlias = "None | str | Line | Body | Sequence[Code]"
|
|
49
52
|
|
|
50
53
|
|
|
@@ -216,9 +219,14 @@ class Body:
|
|
|
216
219
|
"""Append one line verbatim."""
|
|
217
220
|
return self._emit([_line(text)])
|
|
218
221
|
|
|
219
|
-
def lines(self, text: str) -> Body:
|
|
220
|
-
"""Append a margin-stripped, possibly multi-line block of C++.
|
|
221
|
-
|
|
222
|
+
def lines(self, text: str, *, margin: str | None = "|") -> Body:
|
|
223
|
+
"""Append a margin-stripped, possibly multi-line block of C++.
|
|
224
|
+
|
|
225
|
+
``margin=None`` turns the stripping off, for text taken from a generator's
|
|
226
|
+
input that may legitimately begin with the margin character. :meth:`line`
|
|
227
|
+
never strips.
|
|
228
|
+
"""
|
|
229
|
+
return self._emit(_lines(text, margin=margin))
|
|
222
230
|
|
|
223
231
|
def raw(self, ll: Iterable[Line]) -> Body:
|
|
224
232
|
"""Append already-rendered lines."""
|
|
@@ -241,19 +249,19 @@ class Body:
|
|
|
241
249
|
# Comments
|
|
242
250
|
# ------------------------------------------------------------------
|
|
243
251
|
|
|
244
|
-
def comment(self, text:
|
|
252
|
+
def comment(self, text: Comment) -> Body:
|
|
245
253
|
"""Append a ``//`` comment with no leading blank line."""
|
|
246
254
|
return self._emit(write_comment_body(text))
|
|
247
255
|
|
|
248
|
-
def spaced_comment(self, text:
|
|
256
|
+
def spaced_comment(self, text: Comment) -> Body:
|
|
249
257
|
"""Append a ``//`` comment preceded by a blank line."""
|
|
250
258
|
return self._emit(write_comment(text))
|
|
251
259
|
|
|
252
|
-
def doc_comment(self, text:
|
|
260
|
+
def doc_comment(self, text: Comment) -> Body:
|
|
253
261
|
"""Append a ``//!`` doxygen comment."""
|
|
254
262
|
return self._emit(write_doxygen_comment(text))
|
|
255
263
|
|
|
256
|
-
def banner(self, text:
|
|
264
|
+
def banner(self, text: Comment) -> Body:
|
|
257
265
|
"""Append a ruled banner comment."""
|
|
258
266
|
return self._emit(write_banner_comment(text))
|
|
259
267
|
|
|
@@ -95,3 +95,14 @@ def _extends(extends: str | Sequence[str] | None) -> str | None:
|
|
|
95
95
|
return extends
|
|
96
96
|
joined = ", ".join(extends)
|
|
97
97
|
return joined or None
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _as_attributes(attributes: str | Sequence[str]) -> tuple[str, ...]:
|
|
101
|
+
"""Normalise a declaration-attribute specification into a tuple.
|
|
102
|
+
|
|
103
|
+
A single string is one attribute, not a sequence of characters, since one is the
|
|
104
|
+
common case: ``attributes='__attribute__((visibility("default")))'``.
|
|
105
|
+
"""
|
|
106
|
+
if isinstance(attributes, str):
|
|
107
|
+
return (attributes,)
|
|
108
|
+
return tuple(attributes)
|
|
@@ -12,6 +12,7 @@ from typing import TYPE_CHECKING, Any
|
|
|
12
12
|
from ..comments import write_access_tag, write_banner_comment
|
|
13
13
|
from ..doc import (
|
|
14
14
|
Class,
|
|
15
|
+
Comment,
|
|
15
16
|
Constructor,
|
|
16
17
|
Destructor,
|
|
17
18
|
Function,
|
|
@@ -90,7 +91,7 @@ class _SectionBanner(_Builder[Lines]):
|
|
|
90
91
|
definitions went.
|
|
91
92
|
"""
|
|
92
93
|
|
|
93
|
-
def __init__(self, comment:
|
|
94
|
+
def __init__(self, comment: Comment) -> None:
|
|
94
95
|
self.comment = comment
|
|
95
96
|
self.members: list[object] = []
|
|
96
97
|
|
|
@@ -179,7 +180,7 @@ class AccessSection:
|
|
|
179
180
|
its label and banner back out again.
|
|
180
181
|
"""
|
|
181
182
|
|
|
182
|
-
def __init__(self, scope: ClassBuilder, tag: str, comment:
|
|
183
|
+
def __init__(self, scope: ClassBuilder, tag: str, comment: Comment | None) -> None:
|
|
183
184
|
self._scope = scope
|
|
184
185
|
self._count = 1
|
|
185
186
|
scope._add(Lines(write_access_tag(tag), Output.HPP))
|
|
@@ -11,12 +11,22 @@ from ..comments import (
|
|
|
11
11
|
write_doxygen_comment,
|
|
12
12
|
write_doxygen_comment_opt,
|
|
13
13
|
)
|
|
14
|
-
from ..doc import
|
|
14
|
+
from ..doc import (
|
|
15
|
+
Comment,
|
|
16
|
+
Constructor,
|
|
17
|
+
Destructor,
|
|
18
|
+
Function,
|
|
19
|
+
Lines,
|
|
20
|
+
Output,
|
|
21
|
+
Param,
|
|
22
|
+
Type,
|
|
23
|
+
as_type,
|
|
24
|
+
)
|
|
15
25
|
from ..errors import ValidationError
|
|
16
26
|
from ..lines import Line, wrap_in_scope
|
|
17
27
|
from ..lines import line as _line
|
|
18
28
|
from .base import _Builder
|
|
19
|
-
from .coercion import _as_body_lines, _as_params, _sv_qualifier
|
|
29
|
+
from .coercion import _as_attributes, _as_body_lines, _as_params, _sv_qualifier
|
|
20
30
|
|
|
21
31
|
|
|
22
32
|
class Radix(Enum):
|
|
@@ -53,7 +63,7 @@ class FunctionBuilder(_Builder[Function]):
|
|
|
53
63
|
*,
|
|
54
64
|
ret: Type | str = "void",
|
|
55
65
|
params: Iterable[Param | Sequence[str]] = (),
|
|
56
|
-
comment:
|
|
66
|
+
comment: Comment | None = None,
|
|
57
67
|
body: Code = None,
|
|
58
68
|
const: bool = False,
|
|
59
69
|
static: bool = False,
|
|
@@ -66,6 +76,8 @@ class FunctionBuilder(_Builder[Function]):
|
|
|
66
76
|
noexcept: bool = False,
|
|
67
77
|
deleted: bool = False,
|
|
68
78
|
defaulted: bool = False,
|
|
79
|
+
declaration_only: bool = False,
|
|
80
|
+
attributes: str | Sequence[str] = (),
|
|
69
81
|
template: str | None = None,
|
|
70
82
|
inline_body: bool = False,
|
|
71
83
|
cpp_file: str | None = None,
|
|
@@ -81,6 +93,8 @@ class FunctionBuilder(_Builder[Function]):
|
|
|
81
93
|
self.noexcept = noexcept
|
|
82
94
|
self.deleted = deleted
|
|
83
95
|
self.defaulted = defaulted
|
|
96
|
+
self.declaration_only = declaration_only
|
|
97
|
+
self.attributes = _as_attributes(attributes)
|
|
84
98
|
self.template = template
|
|
85
99
|
self.inline_body = inline_body
|
|
86
100
|
self.cpp_file = cpp_file
|
|
@@ -99,7 +113,7 @@ class FunctionBuilder(_Builder[Function]):
|
|
|
99
113
|
type_name: Type | str,
|
|
100
114
|
name: str,
|
|
101
115
|
*,
|
|
102
|
-
comment:
|
|
116
|
+
comment: Comment | None = None,
|
|
103
117
|
default: str | None = None,
|
|
104
118
|
) -> FunctionBuilder:
|
|
105
119
|
"""Append one formal parameter. Returns self, so calls can be chained."""
|
|
@@ -125,6 +139,8 @@ class FunctionBuilder(_Builder[Function]):
|
|
|
125
139
|
noexcept=self.noexcept,
|
|
126
140
|
deleted=self.deleted,
|
|
127
141
|
defaulted=self.defaulted,
|
|
142
|
+
declaration_only=self.declaration_only,
|
|
143
|
+
attributes=self.attributes,
|
|
128
144
|
template=self.template,
|
|
129
145
|
inline_body=self.inline_body,
|
|
130
146
|
cpp_file=self.cpp_file,
|
|
@@ -145,13 +161,14 @@ class ConstructorBuilder(_Builder[Constructor]):
|
|
|
145
161
|
*,
|
|
146
162
|
params: Iterable[Param | Sequence[str]] = (),
|
|
147
163
|
initializers: Iterable[str] = (),
|
|
148
|
-
comment:
|
|
164
|
+
comment: Comment | None = None,
|
|
149
165
|
body: Code = None,
|
|
150
166
|
explicit: bool = False,
|
|
151
167
|
constexpr: bool = False,
|
|
152
168
|
noexcept: bool = False,
|
|
153
169
|
deleted: bool = False,
|
|
154
170
|
defaulted: bool = False,
|
|
171
|
+
declaration_only: bool = False,
|
|
155
172
|
template: str | None = None,
|
|
156
173
|
inline_body: bool = False,
|
|
157
174
|
cpp_file: str | None = None,
|
|
@@ -162,6 +179,7 @@ class ConstructorBuilder(_Builder[Constructor]):
|
|
|
162
179
|
self.noexcept = noexcept
|
|
163
180
|
self.deleted = deleted
|
|
164
181
|
self.defaulted = defaulted
|
|
182
|
+
self.declaration_only = declaration_only
|
|
165
183
|
self.template = template
|
|
166
184
|
self.inline_body = inline_body
|
|
167
185
|
self.cpp_file = cpp_file
|
|
@@ -174,7 +192,7 @@ class ConstructorBuilder(_Builder[Constructor]):
|
|
|
174
192
|
type_name: Type | str,
|
|
175
193
|
name: str,
|
|
176
194
|
*,
|
|
177
|
-
comment:
|
|
195
|
+
comment: Comment | None = None,
|
|
178
196
|
default: str | None = None,
|
|
179
197
|
) -> ConstructorBuilder:
|
|
180
198
|
"""Append one formal parameter."""
|
|
@@ -202,6 +220,7 @@ class ConstructorBuilder(_Builder[Constructor]):
|
|
|
202
220
|
noexcept=self.noexcept,
|
|
203
221
|
deleted=self.deleted,
|
|
204
222
|
defaulted=self.defaulted,
|
|
223
|
+
declaration_only=self.declaration_only,
|
|
205
224
|
template=self.template,
|
|
206
225
|
inline_body=self.inline_body,
|
|
207
226
|
cpp_file=self.cpp_file,
|
|
@@ -220,13 +239,14 @@ class DestructorBuilder(_Builder[Destructor]):
|
|
|
220
239
|
def __init__(
|
|
221
240
|
self,
|
|
222
241
|
*,
|
|
223
|
-
comment:
|
|
242
|
+
comment: Comment | None = None,
|
|
224
243
|
body: Code = None,
|
|
225
244
|
virtual: bool = False,
|
|
226
245
|
override: bool = False,
|
|
227
246
|
noexcept: bool = False,
|
|
228
247
|
deleted: bool = False,
|
|
229
248
|
defaulted: bool = False,
|
|
249
|
+
declaration_only: bool = False,
|
|
230
250
|
inline_body: bool = False,
|
|
231
251
|
cpp_file: str | None = None,
|
|
232
252
|
) -> None:
|
|
@@ -236,6 +256,7 @@ class DestructorBuilder(_Builder[Destructor]):
|
|
|
236
256
|
self.noexcept = noexcept
|
|
237
257
|
self.deleted = deleted
|
|
238
258
|
self.defaulted = defaulted
|
|
259
|
+
self.declaration_only = declaration_only
|
|
239
260
|
self.inline_body = inline_body
|
|
240
261
|
self.cpp_file = cpp_file
|
|
241
262
|
self.body = Body(_as_body_lines(body))
|
|
@@ -249,6 +270,7 @@ class DestructorBuilder(_Builder[Destructor]):
|
|
|
249
270
|
noexcept=self.noexcept,
|
|
250
271
|
deleted=self.deleted,
|
|
251
272
|
defaulted=self.defaulted,
|
|
273
|
+
declaration_only=self.declaration_only,
|
|
252
274
|
inline_body=self.inline_body,
|
|
253
275
|
cpp_file=self.cpp_file,
|
|
254
276
|
)
|
|
@@ -269,7 +291,7 @@ class EnumBuilder(_Builder[Lines]):
|
|
|
269
291
|
*,
|
|
270
292
|
underlying: str | None = None,
|
|
271
293
|
scoped: bool = False,
|
|
272
|
-
comment:
|
|
294
|
+
comment: Comment | None = None,
|
|
273
295
|
output: Output = Output.HPP,
|
|
274
296
|
cpp_file: str | None = None,
|
|
275
297
|
radix: Radix = Radix.DECIMAL,
|
|
@@ -323,7 +345,7 @@ class EnumBuilder(_Builder[Lines]):
|
|
|
323
345
|
name: str,
|
|
324
346
|
value: int | str | None = None,
|
|
325
347
|
*,
|
|
326
|
-
comment:
|
|
348
|
+
comment: Comment | None = None,
|
|
327
349
|
radix: Radix | None = None,
|
|
328
350
|
) -> EnumBuilder:
|
|
329
351
|
"""Append one enumerator.
|
|
@@ -10,7 +10,8 @@ from ..doc import CppDoc, FileBanner, HppFile
|
|
|
10
10
|
from ..errors import ValidationError
|
|
11
11
|
from ..formatting import Formatter
|
|
12
12
|
from ..output import WriteResult, doc_files, write_doc
|
|
13
|
-
from ..
|
|
13
|
+
from ..validation import check_document
|
|
14
|
+
from ..writer import CppWriter, HppWriter, render_cpp, render_hpp
|
|
14
15
|
from .base import _DocContext
|
|
15
16
|
from .scopes import _MemberScope
|
|
16
17
|
|
|
@@ -28,8 +29,13 @@ class CppDocBuilder(_MemberScope[CppDoc]):
|
|
|
28
29
|
tool_name: str | None = None,
|
|
29
30
|
file_banner: FileBanner | None = None,
|
|
30
31
|
formatter: Formatter | None = None,
|
|
32
|
+
hpp_writer: HppWriter | None = None,
|
|
33
|
+
cpp_writer: CppWriter | None = None,
|
|
31
34
|
hpp_extension: str = "hpp",
|
|
32
35
|
cpp_extension: str = "cpp",
|
|
36
|
+
emit_hpp: bool = True,
|
|
37
|
+
emit_cpp: bool = True,
|
|
38
|
+
strict: bool = False,
|
|
33
39
|
) -> None:
|
|
34
40
|
"""Start a document whose files are named after ``file_base``.
|
|
35
41
|
|
|
@@ -39,7 +45,20 @@ class CppDocBuilder(_MemberScope[CppDoc]):
|
|
|
39
45
|
|
|
40
46
|
``formatter`` post-processes every file this document renders; see
|
|
41
47
|
:mod:`fprime_cpp_codegen.formatting`. Any render or write call can override
|
|
42
|
-
it, but cannot switch it off.
|
|
48
|
+
it, but cannot switch it off. ``hpp_writer`` and ``cpp_writer`` work the same
|
|
49
|
+
way, substituting a :class:`~fprime_cpp_codegen.writer.DocWriter` subclass for
|
|
50
|
+
the default rendering.
|
|
51
|
+
|
|
52
|
+
``emit_hpp=False`` or ``emit_cpp=False`` makes this a one-file document, which
|
|
53
|
+
a translation unit holding only a module-initialisation block wants. Members
|
|
54
|
+
that would then have nowhere to go raise :class:`ValidationError` when the
|
|
55
|
+
document is built, rather than disappearing.
|
|
56
|
+
|
|
57
|
+
``strict=True`` additionally rejects any definition that needs a body and has
|
|
58
|
+
none, which would otherwise render as an empty out-of-line definition -- valid
|
|
59
|
+
C++, and so easy for a generator to emit by accident. Say
|
|
60
|
+
``declaration_only=True`` to declare without defining, or ``body=""`` for a
|
|
61
|
+
definition that is deliberately empty.
|
|
43
62
|
"""
|
|
44
63
|
super().__init__(_DocContext())
|
|
45
64
|
if not file_base:
|
|
@@ -52,6 +71,23 @@ class CppDocBuilder(_MemberScope[CppDoc]):
|
|
|
52
71
|
self.formatter = formatter
|
|
53
72
|
"""Applied to every file this document renders, unless a call overrides it."""
|
|
54
73
|
|
|
74
|
+
self.hpp_writer = hpp_writer
|
|
75
|
+
"""Renders the header, unless a call overrides it. ``None`` uses
|
|
76
|
+
:class:`~fprime_cpp_codegen.writer.HppWriter`."""
|
|
77
|
+
|
|
78
|
+
self.cpp_writer = cpp_writer
|
|
79
|
+
"""Renders the source files, unless a call overrides it. ``None`` uses
|
|
80
|
+
:class:`~fprime_cpp_codegen.writer.CppWriter`."""
|
|
81
|
+
|
|
82
|
+
self.emit_hpp = emit_hpp
|
|
83
|
+
"""Whether this document produces a header at all."""
|
|
84
|
+
|
|
85
|
+
self.emit_cpp = emit_cpp
|
|
86
|
+
"""Whether this document produces any source file at all."""
|
|
87
|
+
|
|
88
|
+
self.strict = strict
|
|
89
|
+
"""Whether :meth:`build` rejects a definition that needs a body and has none."""
|
|
90
|
+
|
|
55
91
|
self.file_banner = file_banner
|
|
56
92
|
"""Overrides the ``\\title``/``\\author``/``\\brief`` block atop each file.
|
|
57
93
|
Distinct from :meth:`banner`, which emits a section comment."""
|
|
@@ -73,7 +109,8 @@ class CppDocBuilder(_MemberScope[CppDoc]):
|
|
|
73
109
|
return f"{self.file_base}.{self.cpp_extension}"
|
|
74
110
|
|
|
75
111
|
def build(self) -> CppDoc:
|
|
76
|
-
|
|
112
|
+
"""Produce the IR, checking it against ``emit_hpp``/``emit_cpp``/``strict``."""
|
|
113
|
+
doc = CppDoc(
|
|
77
114
|
description=self.description,
|
|
78
115
|
hpp_file=HppFile(self.hpp_name, self.include_guard),
|
|
79
116
|
cpp_file_name=self.cpp_name,
|
|
@@ -81,23 +118,55 @@ class CppDocBuilder(_MemberScope[CppDoc]):
|
|
|
81
118
|
tool_name=self.tool_name,
|
|
82
119
|
banner=self.file_banner,
|
|
83
120
|
)
|
|
121
|
+
check_document(
|
|
122
|
+
doc,
|
|
123
|
+
emit_hpp=self.emit_hpp,
|
|
124
|
+
emit_cpp=self.emit_cpp,
|
|
125
|
+
strict=self.strict,
|
|
126
|
+
)
|
|
127
|
+
return doc
|
|
84
128
|
|
|
85
129
|
# -- output -------------------------------------------------------
|
|
86
130
|
|
|
87
131
|
def _formatter(self, override: Formatter | None) -> Formatter | None:
|
|
88
132
|
return override if override is not None else self.formatter
|
|
89
133
|
|
|
90
|
-
def
|
|
134
|
+
def _hpp_writer(self, override: HppWriter | None) -> HppWriter | None:
|
|
135
|
+
return override if override is not None else self.hpp_writer
|
|
136
|
+
|
|
137
|
+
def _cpp_writer(self, override: CppWriter | None) -> CppWriter | None:
|
|
138
|
+
return override if override is not None else self.cpp_writer
|
|
139
|
+
|
|
140
|
+
def _require_emitted(self, which: str) -> None:
|
|
141
|
+
"""Reject rendering a file this document was told not to produce."""
|
|
142
|
+
if not (self.emit_hpp if which == "hpp" else self.emit_cpp):
|
|
143
|
+
raise ValidationError(
|
|
144
|
+
f"this document was built with emit_{which}=False, so it has no "
|
|
145
|
+
f"{which} file to render"
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
def render_hpp(
|
|
149
|
+
self,
|
|
150
|
+
*,
|
|
151
|
+
formatter: Formatter | None = None,
|
|
152
|
+
writer: HppWriter | None = None,
|
|
153
|
+
) -> str:
|
|
91
154
|
"""Render the header as text."""
|
|
92
|
-
|
|
155
|
+
self._require_emitted("hpp")
|
|
156
|
+
text = render_hpp(self.build(), writer=self._hpp_writer(writer))
|
|
93
157
|
chosen = self._formatter(formatter)
|
|
94
158
|
return chosen(text, self.hpp_name) if chosen else text
|
|
95
159
|
|
|
96
160
|
def render_cpp(
|
|
97
|
-
self,
|
|
161
|
+
self,
|
|
162
|
+
cpp_file: str | None = None,
|
|
163
|
+
*,
|
|
164
|
+
formatter: Formatter | None = None,
|
|
165
|
+
writer: CppWriter | None = None,
|
|
98
166
|
) -> str:
|
|
99
167
|
"""Render one source file as text. ``None`` selects the default one."""
|
|
100
|
-
|
|
168
|
+
self._require_emitted("cpp")
|
|
169
|
+
text = render_cpp(self.build(), cpp_file, writer=self._cpp_writer(writer))
|
|
101
170
|
chosen = self._formatter(formatter)
|
|
102
171
|
if not chosen:
|
|
103
172
|
return text
|
|
@@ -109,9 +178,19 @@ class CppDocBuilder(_MemberScope[CppDoc]):
|
|
|
109
178
|
cpp_files: Sequence[str] | None = None,
|
|
110
179
|
*,
|
|
111
180
|
formatter: Formatter | None = None,
|
|
181
|
+
hpp_writer: HppWriter | None = None,
|
|
182
|
+
cpp_writer: CppWriter | None = None,
|
|
112
183
|
) -> dict[str, str]:
|
|
113
184
|
"""Render every file this document owns, as a name-to-text mapping."""
|
|
114
|
-
return doc_files(
|
|
185
|
+
return doc_files(
|
|
186
|
+
self.build(),
|
|
187
|
+
cpp_files,
|
|
188
|
+
formatter=self._formatter(formatter),
|
|
189
|
+
hpp_writer=self._hpp_writer(hpp_writer),
|
|
190
|
+
cpp_writer=self._cpp_writer(cpp_writer),
|
|
191
|
+
emit_hpp=self.emit_hpp,
|
|
192
|
+
emit_cpp=self.emit_cpp,
|
|
193
|
+
)
|
|
115
194
|
|
|
116
195
|
def write(
|
|
117
196
|
self,
|
|
@@ -119,6 +198,8 @@ class CppDocBuilder(_MemberScope[CppDoc]):
|
|
|
119
198
|
cpp_files: Sequence[str] | None = None,
|
|
120
199
|
*,
|
|
121
200
|
formatter: Formatter | None = None,
|
|
201
|
+
hpp_writer: HppWriter | None = None,
|
|
202
|
+
cpp_writer: CppWriter | None = None,
|
|
122
203
|
skip_unchanged: bool = True,
|
|
123
204
|
encoding: str = "utf-8",
|
|
124
205
|
) -> WriteResult:
|
|
@@ -131,6 +212,10 @@ class CppDocBuilder(_MemberScope[CppDoc]):
|
|
|
131
212
|
directory,
|
|
132
213
|
cpp_files,
|
|
133
214
|
formatter=self._formatter(formatter),
|
|
215
|
+
hpp_writer=self._hpp_writer(hpp_writer),
|
|
216
|
+
cpp_writer=self._cpp_writer(cpp_writer),
|
|
217
|
+
emit_hpp=self.emit_hpp,
|
|
218
|
+
emit_cpp=self.emit_cpp,
|
|
134
219
|
skip_unchanged=skip_unchanged,
|
|
135
220
|
encoding=encoding,
|
|
136
221
|
)
|