• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aas-core-works / aas-core-codegen / 26632278559

29 May 2026 10:31AM UTC coverage: 84.205% (+0.001%) from 84.204%
26632278559

push

github

web-flow
Upgrade mypy to 2.1.0 (#640)

We upgrade to the latest version of mypy to be able to use type
narrowing on ``x in c`` for when ``x`` is a literal and ``c``
a constant tuple of literals.

6 of 8 new or added lines in 6 files covered. (75.0%)

30047 of 35683 relevant lines covered (84.21%)

2.53 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

60.58
/aas_core_codegen/cpp/lib/_generate_constants.py
1
"""Generate code to define the constants of the meta-model."""
2
import io
3✔
3
from typing import (
3✔
4
    Optional,
5
    List,
6
    Tuple,
7
)
8

9
from icontract import ensure
3✔
10

11
from aas_core_codegen import intermediate
3✔
12
from aas_core_codegen.common import (
3✔
13
    Error,
14
    assert_never,
15
    Stripped,
16
    indent_but_first_line,
17
)
18
from aas_core_codegen.cpp import (
3✔
19
    common as cpp_common,
20
    naming as cpp_naming,
21
    description as cpp_description,
22
)
23
from aas_core_codegen.cpp.common import (
3✔
24
    INDENT as I,
25
    INDENT2 as II,
26
)
27

28

29
def _generate_documentation_comment_for_constant(
3✔
30
    description: intermediate.DescriptionOfConstant,
31
    context: cpp_description.Context,
32
) -> Tuple[Optional[Stripped], Optional[List[Error]]]:
33
    """Generate the documentation comment for the given constant."""
34
    # fmt: off
35
    comment, errors = (
3✔
36
        cpp_description
37
        .generate_comment_for_summary_remarks(
38
            description=description, context=context
39
        )
40
    )
41
    # fmt: on
42

43
    if errors is not None:
3✔
44
        return None, errors
×
45

46
    assert comment is not None
3✔
47
    return comment, None
3✔
48

49

50
@ensure(lambda result: (result[0] is None) ^ (result[1] is None))
3✔
51
def _generate_constant_primitive_definition(
3✔
52
    constant: intermediate.ConstantPrimitive,
53
) -> Tuple[Optional[Stripped], Optional[Error]]:
54
    """Generate the definition of a constant primitive."""
55
    writer = io.StringIO()
×
56

57
    if constant.description is not None:
×
58
        comment, comment_errors = _generate_documentation_comment_for_constant(
×
59
            description=constant.description,
60
            context=cpp_description.Context(
61
                namespace=cpp_common.CONSTANTS_NAMESPACE, cls_or_enum=None
62
            ),
63
        )
64
        if comment_errors is not None:
×
65
            return None, Error(
×
66
                constant.parsed.node,
67
                f"Failed to generate the documentation comment for {constant.name!r}",
68
                comment_errors,
69
            )
70

71
        assert comment is not None
×
72
        writer.write(comment)
×
73
        writer.write("\n")
×
74

75
    constant_name = cpp_naming.constant_name(constant.name)
×
76

77
    if constant.a_type is intermediate.PrimitiveType.BOOL:
×
78
        writer.write(f"extern const bool {constant_name};")
×
79

80
    elif constant.a_type is intermediate.PrimitiveType.INT:
×
81
        writer.write(f"extern const int64_t {constant_name};")
×
82

83
    elif constant.a_type is intermediate.PrimitiveType.FLOAT:
×
84
        writer.write(f"extern const double {constant_name};")
×
85

86
    elif constant.a_type is intermediate.PrimitiveType.STR:
×
87
        writer.write(f"extern const std::wstring {constant_name};")
×
88

89
    elif constant.a_type is intermediate.PrimitiveType.BYTEARRAY:
×
90
        writer.write(f"extern const std::vector<std::uint8_t> {constant_name};")
×
91

92
    else:
93
        # noinspection PyTypeChecker
94
        assert_never(constant.a_type)
×
95

96
    return Stripped(writer.getvalue()), None
×
97

98

99
@ensure(lambda result: (result[0] is None) ^ (result[1] is None))
3✔
100
def _generate_constant_primitive_implementation(
3✔
101
    constant: intermediate.ConstantPrimitive,
102
) -> Tuple[Optional[Stripped], Optional[Error]]:
103
    """Generate the implementation of a constant primitive."""
104
    constant_name = cpp_naming.constant_name(constant.name)
×
105

106
    if constant.a_type is intermediate.PrimitiveType.BOOL:
×
107
        assert isinstance(constant.value, bool)
×
108
        literal = cpp_common.boolean_literal(constant.value)
×
109

110
        return Stripped(f"const bool {constant_name} = {literal};"), None
×
111

112
    elif constant.a_type is intermediate.PrimitiveType.INT:
×
113
        assert isinstance(constant.value, int)
×
114

115
        if constant.value > 2**63 - 1 or constant.value < -(2**63):
×
116
            return None, Error(
×
117
                constant.parsed.node,
118
                f"The value of the constant {constant.name!r} overflows "
119
                f"64-bit signed integer",
120
            )
121
        return Stripped(f"const int64_t {constant_name} = {str(constant.value)};"), None
×
122

123
    elif constant.a_type is intermediate.PrimitiveType.FLOAT:
×
124
        assert isinstance(constant.value, float)
×
125

126
        # NOTE (mristin):
127
        # We assume that the float constants are not meant to be all to precise.
128
        # Therefore, we use a string representation here. However, beware that we
129
        # might have to use a more precise representation in the future if the spec
130
        # change.
131
        literal = cpp_common.float_literal(constant.value)
×
132

133
        return Stripped(f"const double {constant_name} = {literal};"), None
×
134

135
    elif constant.a_type is intermediate.PrimitiveType.STR:
×
136
        assert isinstance(constant.value, str)
×
137
        literal = cpp_common.wstring_literal(constant.value)
×
138

139
        return (
×
140
            Stripped(
141
                f"""\
142
const std::wstring {constant_name} = (
143
{I}{indent_but_first_line(literal, I)}
144
);"""
145
            ),
146
            None,
147
        )
148

149
    elif constant.a_type is intermediate.PrimitiveType.BYTEARRAY:
×
NEW
150
        assert isinstance(constant.value, bytes)
×
151

152
        literal, _ = cpp_common.bytes_literal(value=constant.value)
×
153

154
        return (
×
155
            Stripped(
156
                f"""\
157
const std::vector<std::uint_8> {constant_name} = (
158
{I}{indent_but_first_line(literal, I)}
159
);"""
160
            ),
161
            None,
162
        )
163

164
    else:
165
        # noinspection PyTypeChecker
166
        assert_never(constant.a_type)
×
167

168

169
@ensure(lambda result: (result[0] is None) ^ (result[1] is None))
3✔
170
def _generate_constant_set_of_primitives_definition(
3✔
171
    constant: intermediate.ConstantSetOfPrimitives,
172
) -> Tuple[Optional[Stripped], Optional[Error]]:
173
    """Generate the definition of a constant set of primitives."""
174
    errors = []  # type: List[Error]
3✔
175

176
    writer = io.StringIO()
3✔
177

178
    if constant.description is not None:
3✔
179
        comment, comment_errors = _generate_documentation_comment_for_constant(
3✔
180
            description=constant.description,
181
            context=cpp_description.Context(
182
                namespace=cpp_common.CONSTANTS_NAMESPACE, cls_or_enum=None
183
            ),
184
        )
185
        if comment_errors is not None:
3✔
186
            errors.append(
×
187
                Error(
188
                    constant.parsed.node,
189
                    f"Failed to generate the documentation comment for {constant.name!r}",
190
                    comment_errors,
191
                )
192
            )
193
        else:
194
            assert comment is not None
3✔
195
            writer.write(comment)
3✔
196
            writer.write("\n")
3✔
197

198
    set_type: Optional[str]
199

200
    if constant.a_type is intermediate.PrimitiveType.BOOL:
3✔
201
        set_type = "std::unordered_set<bool>"
×
202

203
    elif constant.a_type is intermediate.PrimitiveType.INT:
3✔
204
        set_type = "std::unordered_set<int64_t>"
×
205

206
    elif constant.a_type is intermediate.PrimitiveType.FLOAT:
3✔
207
        set_type = "std::unordered_set<double>"
×
208

209
    elif constant.a_type is intermediate.PrimitiveType.STR:
3✔
210
        set_type = "std::unordered_set<std::wstring>"
3✔
211

212
    elif constant.a_type is intermediate.PrimitiveType.BYTEARRAY:
×
213
        set_type = "std::unordered_set<std::vector<std::uint8_t>, HashBytes>"
×
214

215
    else:
216
        # noinspection PyTypeChecker
217
        assert_never(constant.a_type)
×
218

219
    constant_name = cpp_naming.constant_name(constant.name)
3✔
220

221
    writer.write(
3✔
222
        f"""\
223
extern const {set_type} {constant_name};"""
224
    )
225

226
    return Stripped(writer.getvalue()), None
3✔
227

228

229
@ensure(lambda result: (result[0] is None) ^ (result[1] is None))
3✔
230
def _generate_constant_set_of_primitives_implementation(
3✔
231
    constant: intermediate.ConstantSetOfPrimitives,
232
) -> Tuple[Optional[Stripped], Optional[Error]]:
233
    """Generate the implementation of a constant set of primitives."""
234
    literal_codes = []  # type: List[str]
3✔
235

236
    set_type: str
237

238
    if constant.a_type is intermediate.PrimitiveType.BOOL:
3✔
239
        set_type = "std::unordered_set<bool>"
×
240

241
        for literal in constant.literals:
×
242
            assert isinstance(literal.value, bool)
×
243
            literal_codes.append(cpp_common.boolean_literal(literal.value))
×
244

245
    elif constant.a_type is intermediate.PrimitiveType.INT:
3✔
246
        set_type = "std::unordered_set<int64_t>"
×
247

248
        for literal in constant.literals:
×
249
            assert isinstance(literal.value, int)
×
250

251
            literal_codes.append(str(literal.value))
×
252

253
    elif constant.a_type is intermediate.PrimitiveType.FLOAT:
3✔
254
        set_type = "std::unordered_set<double>"
×
255

256
        for literal in constant.literals:
×
257
            assert isinstance(literal.value, float)
×
258

259
            literal_codes.append(cpp_common.float_literal(literal.value))
×
260

261
    elif constant.a_type is intermediate.PrimitiveType.STR:
3✔
262
        set_type = "std::unordered_set<std::wstring>"
3✔
263

264
        for literal in constant.literals:
3✔
265
            assert isinstance(literal.value, str)
3✔
266
            literal_codes.append(cpp_common.wstring_literal(literal.value))
3✔
267

268
    elif constant.a_type is intermediate.PrimitiveType.BYTEARRAY:
×
269
        set_type = Stripped(
×
270
            f"""\
271
std::unordered_set<
272
{I}std::vector<std::uint8_t>,
273
{I}HashBytes
274
>"""
275
        )
276

277
        for literal in constant.literals:
×
NEW
278
            assert isinstance(literal.value, bytes)
×
279
            literal_code, _ = cpp_common.bytes_literal(literal.value)
×
280
            literal_codes.append(literal_code)
×
281

282
    else:
283
        # noinspection PyTypeChecker
284
        assert_never(constant.a_type)
×
285

286
    literals_joined = ",\n".join(literal_codes)
3✔
287

288
    constant_name = cpp_naming.constant_name(constant.name)
3✔
289

290
    return (
3✔
291
        Stripped(
292
            f"""\
293
const {set_type} {constant_name} = {{
294
{I}{indent_but_first_line(literals_joined, I)}
295
}};"""
296
        ),
297
        None,
298
    )
299

300

301
@ensure(lambda result: (result[0] is None) ^ (result[1] is None))
3✔
302
def _generate_constant_set_of_enumeration_literals_definition(
3✔
303
    constant: intermediate.ConstantSetOfEnumerationLiterals,
304
) -> Tuple[Optional[Stripped], Optional[Error]]:
305
    """Generate the definition of a constant set of enumeration literals."""
306
    writer = io.StringIO()
3✔
307

308
    if constant.description is not None:
3✔
309
        comment, comment_errors = _generate_documentation_comment_for_constant(
3✔
310
            description=constant.description,
311
            context=cpp_description.Context(
312
                namespace=cpp_common.CONSTANTS_NAMESPACE, cls_or_enum=None
313
            ),
314
        )
315
        if comment_errors is not None:
3✔
316
            return None, Error(
×
317
                constant.parsed.node,
318
                f"Failed to generate the documentation comment for {constant.name!r}",
319
                comment_errors,
320
            )
321

322
        assert comment is not None
3✔
323
        writer.write(comment)
3✔
324
        writer.write("\n")
3✔
325

326
    enum_name = cpp_naming.enum_name(constant.enumeration.name)
3✔
327

328
    constant_name = cpp_naming.constant_name(constant.name)
3✔
329

330
    writer.write(
3✔
331
        f"extern const std::unordered_set<types::{enum_name}> {constant_name};"
332
    )
333

334
    return Stripped(writer.getvalue()), None
3✔
335

336

337
@ensure(lambda result: (result[0] is None) ^ (result[1] is None))
3✔
338
def _generate_constant_set_of_enumeration_literals_implementation(
3✔
339
    constant: intermediate.ConstantSetOfEnumerationLiterals,
340
) -> Tuple[Optional[Stripped], Optional[Error]]:
341
    """Generate the definition of a constant set of enumeration literals."""
342

343
    enum_name = cpp_naming.enum_name(constant.enumeration.name)
3✔
344

345
    literal_codes = []  # type: List[str]
3✔
346
    for literal in constant.literals:
3✔
347
        literal_name = cpp_naming.enum_literal_name(literal.name)
3✔
348

349
        literal_codes.append(f"types::{enum_name}::{literal_name}")
3✔
350

351
    constant_name = cpp_naming.constant_name(constant.name)
3✔
352

353
    literals_joined = ",\n".join(literal_codes)
3✔
354

355
    return (
3✔
356
        Stripped(
357
            f"""\
358
const std::unordered_set<types::{enum_name}> {constant_name} = {{
359
{I}{indent_but_first_line(literals_joined, I)}
360
}};"""
361
        ),
362
        None,
363
    )
364

365

366
# fmt: off
367
@ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
3✔
368
@ensure(
3✔
369
    lambda result:
370
    not (result[0] is not None) or result[0].endswith('\n'),
371
    "Trailing newline mandatory for valid end-of-files"
372
)
373
# fmt: on
374
def generate_header(
3✔
375
    symbol_table: intermediate.SymbolTable,
376
    library_namespace: Stripped,
377
) -> Tuple[Optional[str], Optional[List[Error]]]:
378
    """Generate header to define the constants of the meta-model."""
379
    errors = []  # type: List[Error]
3✔
380

381
    namespace = Stripped(f"{library_namespace}::{cpp_common.CONSTANTS_NAMESPACE}")
3✔
382

383
    include_guard_var = cpp_common.include_guard_var(namespace)
3✔
384

385
    include_prefix_path = cpp_common.generate_include_prefix_path(library_namespace)
3✔
386

387
    blocks = [
3✔
388
        Stripped(
389
            f"""\
390
#ifndef {include_guard_var}
391
#define {include_guard_var}"""
392
        ),
393
        cpp_common.WARNING,
394
        Stripped(
395
            f"""\
396
#include "{include_prefix_path}/types.hpp"
397

398
#pragma warning(push, 0)
399
#include <cstdint>
400
#include <unordered_set>
401
#include <vector>
402
#pragma warning(pop)"""
403
        ),
404
        cpp_common.generate_namespace_opening(library_namespace),
405
        Stripped(
406
            f"""\
407
/**
408
 * \\defgroup constants Pre-defined constants of the meta-model
409
 * @{{
410
 */
411
namespace {cpp_common.CONSTANTS_NAMESPACE} {{"""
412
        ),
413
        Stripped(
414
            f"""\
415
/**
416
 * Hash a blob of bytes based on the Java's String hash.
417
 */
418
struct HashBytes {{
419
{I}std::size_t operator()(const std::vector<std::uint8_t>& bytes) const;
420
}};"""
421
        ),
422
    ]
423

424
    for constant in symbol_table.constants:
3✔
425
        block: Optional[Stripped]
426
        error: Optional[Error]
427

428
        if isinstance(constant, intermediate.ConstantPrimitive):
3✔
429
            block, error = _generate_constant_primitive_definition(constant=constant)
×
430
        elif isinstance(constant, intermediate.ConstantSetOfPrimitives):
3✔
431
            block, error = _generate_constant_set_of_primitives_definition(
3✔
432
                constant=constant
433
            )
434
        elif isinstance(constant, intermediate.ConstantSetOfEnumerationLiterals):
3✔
435
            block, error = _generate_constant_set_of_enumeration_literals_definition(
3✔
436
                constant=constant
437
            )
438
        else:
439
            # noinspection PyTypeChecker
440
            assert_never(constant)
×
441

442
        if error is not None:
3✔
443
            errors.append(error)
×
444
            continue
×
445

446
        assert block is not None
3✔
447
        blocks.append(block)
3✔
448

449
    if len(errors) > 0:
3✔
450
        return None, errors
×
451

452
    blocks.extend(
3✔
453
        [
454
            Stripped(
455
                f"""\
456
}}  // namespace {cpp_common.COMMON_NAMESPACE}
457
/**@}}*/"""
458
            ),
459
            cpp_common.generate_namespace_closing(library_namespace),
460
            cpp_common.WARNING,
461
            Stripped(f"#endif  // {include_guard_var}"),
462
        ]
463
    )
464

465
    writer = io.StringIO()
3✔
466
    for i, block in enumerate(blocks):
3✔
467
        if i > 0:
3✔
468
            writer.write("\n\n")
3✔
469

470
        writer.write(block)
3✔
471

472
    writer.write("\n")
3✔
473

474
    return writer.getvalue(), None
3✔
475

476

477
# fmt: off
478
@ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
3✔
479
@ensure(
3✔
480
    lambda result:
481
    not (result[0] is not None) or result[0].endswith('\n'),
482
    "Trailing newline mandatory for valid end-of-files"
483
)
484
# fmt: on
485
def generate_implementation(
3✔
486
    symbol_table: intermediate.SymbolTable,
487
    library_namespace: Stripped,
488
) -> Tuple[Optional[str], Optional[List[Error]]]:
489
    """Generate implementation to define the constants of the meta-model."""
490
    errors = []  # type: List[Error]
3✔
491

492
    namespace = Stripped(f"{library_namespace}::constants")
3✔
493

494
    include_prefix_path = cpp_common.generate_include_prefix_path(library_namespace)
3✔
495

496
    blocks = [
3✔
497
        Stripped(
498
            f'''\
499
#include "{include_prefix_path}/constants.hpp"'''
500
        ),
501
        cpp_common.WARNING,
502
        cpp_common.generate_namespace_opening(namespace),
503
        Stripped(
504
            f"""\
505
std::size_t HashBytes::operator()(
506
{I}const std::vector<std::uint8_t>& bytes
507
) const {{
508
{I}std::size_t result = 0;
509
{I}const std::size_t prime = 31;
510
{I}const std::size_t size = bytes.size();
511
{I}for (std::size_t i = 0; i < size; ++i) {{
512
{II}result = bytes[i] + (result * prime);
513
{I}}}
514
{I}return result;
515
}}"""
516
        ),
517
    ]
518

519
    for constant in symbol_table.constants:
3✔
520
        block: Optional[Stripped]
521
        error: Optional[Error]
522

523
        if isinstance(constant, intermediate.ConstantPrimitive):
3✔
524
            block, error = _generate_constant_primitive_implementation(
×
525
                constant=constant
526
            )
527
        elif isinstance(constant, intermediate.ConstantSetOfPrimitives):
3✔
528
            block, error = _generate_constant_set_of_primitives_implementation(
3✔
529
                constant=constant
530
            )
531
        elif isinstance(constant, intermediate.ConstantSetOfEnumerationLiterals):
3✔
532
            (
3✔
533
                block,
534
                error,
535
            ) = _generate_constant_set_of_enumeration_literals_implementation(
536
                constant=constant
537
            )
538
        else:
539
            # noinspection PyTypeChecker
540
            assert_never(constant)
×
541

542
        if error is not None:
3✔
543
            errors.append(error)
×
544
            continue
×
545

546
        assert block is not None
3✔
547
        blocks.append(block)
3✔
548

549
    if len(errors) > 0:
3✔
550
        return None, errors
×
551

552
    blocks.extend(
3✔
553
        [
554
            cpp_common.generate_namespace_closing(namespace),
555
            cpp_common.WARNING,
556
        ]
557
    )
558

559
    writer = io.StringIO()
3✔
560
    for i, block in enumerate(blocks):
3✔
561
        if i > 0:
3✔
562
            writer.write("\n\n")
3✔
563

564
        writer.write(block)
3✔
565

566
    writer.write("\n")
3✔
567

568
    return writer.getvalue(), None
3✔
569

570

571
assert generate_header.__doc__ is not None
3✔
572
cpp_common.assert_module_docstring_and_generate_header_consistent(
3✔
573
    module_doc=__doc__, generate_header_doc=generate_header.__doc__
574
)
575

576
assert generate_implementation.__doc__ is not None
3✔
577
cpp_common.assert_module_docstring_and_generate_implementation_consistent(
3✔
578
    module_doc=__doc__, generate_implementation_doc=generate_implementation.__doc__
579
)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc