aas-core-codegen 0.0.16__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.
- aas_core_codegen/__init__.py +6 -0
- aas_core_codegen/__main__.py +8 -0
- aas_core_codegen/common.py +500 -0
- aas_core_codegen/cpp/__init__.py +1 -0
- aas_core_codegen/cpp/aas_common/__init__.py +6 -0
- aas_core_codegen/cpp/aas_common/_generate.py +713 -0
- aas_core_codegen/cpp/common.py +681 -0
- aas_core_codegen/cpp/constants/__init__.py +6 -0
- aas_core_codegen/cpp/constants/_generate.py +568 -0
- aas_core_codegen/cpp/description.py +654 -0
- aas_core_codegen/cpp/enhancing/__init__.py +4 -0
- aas_core_codegen/cpp/enhancing/_generate.py +993 -0
- aas_core_codegen/cpp/iteration/__init__.py +6 -0
- aas_core_codegen/cpp/iteration/_generate.py +2332 -0
- aas_core_codegen/cpp/jsonization/__init__.py +6 -0
- aas_core_codegen/cpp/jsonization/_generate.py +2619 -0
- aas_core_codegen/cpp/main.py +694 -0
- aas_core_codegen/cpp/naming.py +170 -0
- aas_core_codegen/cpp/optionaling.py +557 -0
- aas_core_codegen/cpp/pattern/__init__.py +6 -0
- aas_core_codegen/cpp/pattern/_generate.py +508 -0
- aas_core_codegen/cpp/revm/__init__.py +6 -0
- aas_core_codegen/cpp/revm/_generate.py +1149 -0
- aas_core_codegen/cpp/stringification/__init__.py +5 -0
- aas_core_codegen/cpp/stringification/_generate.py +955 -0
- aas_core_codegen/cpp/structure/__init__.py +7 -0
- aas_core_codegen/cpp/structure/_generate.py +1503 -0
- aas_core_codegen/cpp/transpilation.py +1383 -0
- aas_core_codegen/cpp/unrolling.py +159 -0
- aas_core_codegen/cpp/verification/__init__.py +6 -0
- aas_core_codegen/cpp/verification/_generate.py +3073 -0
- aas_core_codegen/cpp/visitation/__init__.py +6 -0
- aas_core_codegen/cpp/visitation/_generate.py +521 -0
- aas_core_codegen/cpp/wstringification/__init__.py +5 -0
- aas_core_codegen/cpp/wstringification/_generate.py +586 -0
- aas_core_codegen/cpp/xmlization/__init__.py +6 -0
- aas_core_codegen/cpp/xmlization/_generate.py +5373 -0
- aas_core_codegen/cpp/yielding.py +201 -0
- aas_core_codegen/csharp/__init__.py +1 -0
- aas_core_codegen/csharp/common.py +224 -0
- aas_core_codegen/csharp/constants/__init__.py +5 -0
- aas_core_codegen/csharp/constants/_generate.py +409 -0
- aas_core_codegen/csharp/copying/__init__.py +4 -0
- aas_core_codegen/csharp/copying/_generate.py +498 -0
- aas_core_codegen/csharp/description.py +1103 -0
- aas_core_codegen/csharp/enhancing/__init__.py +4 -0
- aas_core_codegen/csharp/enhancing/_generate.py +667 -0
- aas_core_codegen/csharp/jsonization/__init__.py +4 -0
- aas_core_codegen/csharp/jsonization/_generate.py +1630 -0
- aas_core_codegen/csharp/main.py +421 -0
- aas_core_codegen/csharp/naming.py +157 -0
- aas_core_codegen/csharp/reporting/__init__.py +4 -0
- aas_core_codegen/csharp/reporting/_generate.py +266 -0
- aas_core_codegen/csharp/stringification/__init__.py +4 -0
- aas_core_codegen/csharp/stringification/_generate.py +243 -0
- aas_core_codegen/csharp/structure/__init__.py +6 -0
- aas_core_codegen/csharp/structure/_generate.py +1341 -0
- aas_core_codegen/csharp/transpilation.py +990 -0
- aas_core_codegen/csharp/unrolling.py +211 -0
- aas_core_codegen/csharp/verification/__init__.py +6 -0
- aas_core_codegen/csharp/verification/_generate.py +1457 -0
- aas_core_codegen/csharp/visitation/__init__.py +5 -0
- aas_core_codegen/csharp/visitation/_generate.py +579 -0
- aas_core_codegen/csharp/xmlization/__init__.py +4 -0
- aas_core_codegen/csharp/xmlization/_generate.py +1980 -0
- aas_core_codegen/golang/__init__.py +1 -0
- aas_core_codegen/golang/aas_common/__init__.py +4 -0
- aas_core_codegen/golang/aas_common/_generate.py +152 -0
- aas_core_codegen/golang/common.py +303 -0
- aas_core_codegen/golang/constants/__init__.py +5 -0
- aas_core_codegen/golang/constants/_generate.py +339 -0
- aas_core_codegen/golang/description.py +501 -0
- aas_core_codegen/golang/enhancing/__init__.py +4 -0
- aas_core_codegen/golang/enhancing/_generate.py +527 -0
- aas_core_codegen/golang/jsonization/__init__.py +4 -0
- aas_core_codegen/golang/jsonization/_generate.py +1740 -0
- aas_core_codegen/golang/main.py +368 -0
- aas_core_codegen/golang/naming.py +412 -0
- aas_core_codegen/golang/pointering.py +631 -0
- aas_core_codegen/golang/reporting/__init__.py +4 -0
- aas_core_codegen/golang/reporting/_generate.py +218 -0
- aas_core_codegen/golang/stringification/__init__.py +4 -0
- aas_core_codegen/golang/stringification/_generate.py +394 -0
- aas_core_codegen/golang/structure/__init__.py +6 -0
- aas_core_codegen/golang/structure/_generate.py +1493 -0
- aas_core_codegen/golang/transpilation.py +1191 -0
- aas_core_codegen/golang/unrolling.py +159 -0
- aas_core_codegen/golang/verification/__init__.py +6 -0
- aas_core_codegen/golang/verification/_generate.py +1513 -0
- aas_core_codegen/golang/xmlization/__init__.py +4 -0
- aas_core_codegen/golang/xmlization/_generate.py +2507 -0
- aas_core_codegen/infer_for_schema/__init__.py +21 -0
- aas_core_codegen/infer_for_schema/_inline.py +693 -0
- aas_core_codegen/infer_for_schema/_len.py +527 -0
- aas_core_codegen/infer_for_schema/_pattern.py +311 -0
- aas_core_codegen/infer_for_schema/_set.py +394 -0
- aas_core_codegen/infer_for_schema/_stringify.py +201 -0
- aas_core_codegen/infer_for_schema/_types.py +135 -0
- aas_core_codegen/infer_for_schema/match.py +122 -0
- aas_core_codegen/intermediate/__init__.py +78 -0
- aas_core_codegen/intermediate/_hierarchy.py +397 -0
- aas_core_codegen/intermediate/_stringify.py +989 -0
- aas_core_codegen/intermediate/_translate.py +5128 -0
- aas_core_codegen/intermediate/_types.py +2901 -0
- aas_core_codegen/intermediate/construction.py +750 -0
- aas_core_codegen/intermediate/doc.py +344 -0
- aas_core_codegen/intermediate/pattern_verification.py +428 -0
- aas_core_codegen/intermediate/revm.py +985 -0
- aas_core_codegen/intermediate/type_inference.py +2266 -0
- aas_core_codegen/java/__init__.py +1 -0
- aas_core_codegen/java/common.py +197 -0
- aas_core_codegen/java/constants/__init__.py +5 -0
- aas_core_codegen/java/constants/_generate.py +334 -0
- aas_core_codegen/java/copying/__init__.py +4 -0
- aas_core_codegen/java/copying/_generate.py +502 -0
- aas_core_codegen/java/description.py +774 -0
- aas_core_codegen/java/enhancing/__init__.py +4 -0
- aas_core_codegen/java/enhancing/_generate.py +820 -0
- aas_core_codegen/java/generation/__init__.py +5 -0
- aas_core_codegen/java/generation/_generate.py +285 -0
- aas_core_codegen/java/jsonization/__init__.py +4 -0
- aas_core_codegen/java/jsonization/_generate.py +1472 -0
- aas_core_codegen/java/main.py +438 -0
- aas_core_codegen/java/naming.py +187 -0
- aas_core_codegen/java/optional.py +514 -0
- aas_core_codegen/java/reporting/__init__.py +4 -0
- aas_core_codegen/java/reporting/_generate.py +248 -0
- aas_core_codegen/java/stringification/__init__.py +4 -0
- aas_core_codegen/java/stringification/_generate.py +212 -0
- aas_core_codegen/java/structure/__init__.py +6 -0
- aas_core_codegen/java/structure/_generate.py +1767 -0
- aas_core_codegen/java/transpilation.py +1111 -0
- aas_core_codegen/java/verification/__init__.py +6 -0
- aas_core_codegen/java/verification/_generate.py +1536 -0
- aas_core_codegen/java/visitation/__init__.py +5 -0
- aas_core_codegen/java/visitation/_generate.py +689 -0
- aas_core_codegen/java/xmlization/__init__.py +4 -0
- aas_core_codegen/java/xmlization/_generate.py +2274 -0
- aas_core_codegen/jsonld/__init__.py +1 -0
- aas_core_codegen/jsonld/main.py +455 -0
- aas_core_codegen/jsonschema/__init__.py +1 -0
- aas_core_codegen/jsonschema/main.py +982 -0
- aas_core_codegen/main.py +245 -0
- aas_core_codegen/naming.py +133 -0
- aas_core_codegen/opcua/__init__.py +1 -0
- aas_core_codegen/opcua/main.py +1525 -0
- aas_core_codegen/opcua/naming.py +126 -0
- aas_core_codegen/parse/__init__.py +46 -0
- aas_core_codegen/parse/_rules.py +796 -0
- aas_core_codegen/parse/_stringify.py +532 -0
- aas_core_codegen/parse/_translate.py +3940 -0
- aas_core_codegen/parse/_types.py +973 -0
- aas_core_codegen/parse/retree/__init__.py +46 -0
- aas_core_codegen/parse/retree/_fix.py +434 -0
- aas_core_codegen/parse/retree/_parse.py +1143 -0
- aas_core_codegen/parse/retree/_render.py +298 -0
- aas_core_codegen/parse/retree/_stringify.py +199 -0
- aas_core_codegen/parse/retree/_types.py +362 -0
- aas_core_codegen/parse/retree/_visitor.py +70 -0
- aas_core_codegen/parse/tree.py +1303 -0
- aas_core_codegen/protobuf/__init__.py +1 -0
- aas_core_codegen/protobuf/common.py +225 -0
- aas_core_codegen/protobuf/description.py +1102 -0
- aas_core_codegen/protobuf/main.py +115 -0
- aas_core_codegen/protobuf/naming.py +143 -0
- aas_core_codegen/protobuf/structure/__init__.py +6 -0
- aas_core_codegen/protobuf/structure/_generate.py +502 -0
- aas_core_codegen/py.typed +1 -0
- aas_core_codegen/python/__init__.py +1 -0
- aas_core_codegen/python/aas_common/__init__.py +4 -0
- aas_core_codegen/python/aas_common/_generate.py +63 -0
- aas_core_codegen/python/common.py +406 -0
- aas_core_codegen/python/constants/__init__.py +5 -0
- aas_core_codegen/python/constants/_generate.py +377 -0
- aas_core_codegen/python/description.py +508 -0
- aas_core_codegen/python/jsonization/__init__.py +4 -0
- aas_core_codegen/python/jsonization/_generate.py +1391 -0
- aas_core_codegen/python/main.py +323 -0
- aas_core_codegen/python/naming.py +255 -0
- aas_core_codegen/python/stringification/__init__.py +4 -0
- aas_core_codegen/python/stringification/_generate.py +129 -0
- aas_core_codegen/python/structure/__init__.py +6 -0
- aas_core_codegen/python/structure/_generate.py +1801 -0
- aas_core_codegen/python/transpilation.py +958 -0
- aas_core_codegen/python/unrolling.py +156 -0
- aas_core_codegen/python/verification/__init__.py +6 -0
- aas_core_codegen/python/verification/_generate.py +1471 -0
- aas_core_codegen/python/xmlization/__init__.py +4 -0
- aas_core_codegen/python/xmlization/_generate.py +3003 -0
- aas_core_codegen/python_protobuf/__init__.py +1 -0
- aas_core_codegen/python_protobuf/main.py +1424 -0
- aas_core_codegen/python_protobuf/naming.py +85 -0
- aas_core_codegen/rdf_shacl/__init__.py +1 -0
- aas_core_codegen/rdf_shacl/_description.py +351 -0
- aas_core_codegen/rdf_shacl/common.py +206 -0
- aas_core_codegen/rdf_shacl/main.py +114 -0
- aas_core_codegen/rdf_shacl/naming.py +145 -0
- aas_core_codegen/rdf_shacl/rdf.py +435 -0
- aas_core_codegen/rdf_shacl/shacl.py +453 -0
- aas_core_codegen/run.py +124 -0
- aas_core_codegen/smoke/__init__.py +1 -0
- aas_core_codegen/smoke/main.py +219 -0
- aas_core_codegen/specific_implementations.py +72 -0
- aas_core_codegen/stringify.py +333 -0
- aas_core_codegen/typescript/__init__.py +1 -0
- aas_core_codegen/typescript/aas_common/__init__.py +4 -0
- aas_core_codegen/typescript/aas_common/_generate.py +472 -0
- aas_core_codegen/typescript/common.py +340 -0
- aas_core_codegen/typescript/constants/__init__.py +5 -0
- aas_core_codegen/typescript/constants/_generate.py +347 -0
- aas_core_codegen/typescript/description.py +530 -0
- aas_core_codegen/typescript/jsonization/__init__.py +4 -0
- aas_core_codegen/typescript/jsonization/_generate.py +1510 -0
- aas_core_codegen/typescript/main.py +258 -0
- aas_core_codegen/typescript/naming.py +189 -0
- aas_core_codegen/typescript/stringification/__init__.py +4 -0
- aas_core_codegen/typescript/stringification/_generate.py +367 -0
- aas_core_codegen/typescript/structure/__init__.py +6 -0
- aas_core_codegen/typescript/structure/_generate.py +2500 -0
- aas_core_codegen/typescript/transpilation.py +1051 -0
- aas_core_codegen/typescript/unrolling.py +159 -0
- aas_core_codegen/typescript/verification/__init__.py +6 -0
- aas_core_codegen/typescript/verification/_generate.py +1578 -0
- aas_core_codegen/xsd/__init__.py +1 -0
- aas_core_codegen/xsd/main.py +1187 -0
- aas_core_codegen/xsd/naming.py +83 -0
- aas_core_codegen/yielding/__init__.py +1 -0
- aas_core_codegen/yielding/flow.py +139 -0
- aas_core_codegen/yielding/linear.py +754 -0
- aas_core_codegen-0.0.16.dist-info/METADATA +211 -0
- aas_core_codegen-0.0.16.dist-info/RECORD +604 -0
- aas_core_codegen-0.0.16.dist-info/WHEEL +5 -0
- aas_core_codegen-0.0.16.dist-info/entry_points.txt +3 -0
- aas_core_codegen-0.0.16.dist-info/licenses/AUTHORS +9 -0
- aas_core_codegen-0.0.16.dist-info/licenses/LICENSE +23 -0
- aas_core_codegen-0.0.16.dist-info/top_level.txt +2 -0
- dev/continuous_integration/__init__.py +1 -0
- dev/continuous_integration/check_help_in_readme.py +208 -0
- dev/continuous_integration/check_init_and_pyproject_consistent.py +154 -0
- dev/continuous_integration/precommit.py +400 -0
- dev/dev_scripts/__init__.py +1 -0
- dev/dev_scripts/compare_rendered_regexes_against_source_py.py +42 -0
- dev/dev_scripts/copy_to_aas_core3_cpp.py +100 -0
- dev/dev_scripts/copy_to_aas_core3_java.py +90 -0
- dev/dev_scripts/download_latest_aas_core_meta_v3.py +114 -0
- dev/dev_scripts/draw_bipartite_graph_based_on_lines.py +37 -0
- dev/dev_scripts/run_tests_with_rerecord.py +69 -0
- dev/dev_scripts/update_to_aas_core_meta.py +174 -0
- dev/integration_tests/input/jsonschema/boilerplate/main.py +55 -0
- dev/integration_tests/input/meta_model.py +38 -0
- dev/integration_tests/input/python/boilerplate/main.py +153 -0
- dev/integration_tests/main.py +258 -0
- dev/test_data/csharp/test_structure/concrete_class_with_descendants/meta_model.py +15 -0
- dev/test_data/csharp/test_structure/constructor_without_arguments/all_properties_optional/meta_model.py +9 -0
- dev/test_data/csharp/test_structure/constructor_without_arguments/no_properties/meta_model.py +6 -0
- dev/test_data/csharp/test_verification/builtin_functions/len/on_list/meta_model.py +20 -0
- dev/test_data/csharp/test_verification/builtin_functions/len/on_str/meta_model.py +16 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_as_literal/as_prefix/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_as_literal/as_suffix/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_as_literal/in_group_with_quantifier/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_as_literal/in_the_middle/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_as_literal/in_union/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_as_literal/single_utf32_literal/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_as_literal/with_quantifier_within_group/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_as_literal/with_quantifier_without_group/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/literal/at_the_beginning/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/literal/at_the_end/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/literal/in_the_middle/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/literal/multiple/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/literal/single/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/literal/single_with_quantifier/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/range/mixed_with_non_utf32/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/range/more_than_two_high_surrogates/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/range/multiple_utf32_ranges/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/range/multiple_utf32_ranges_mixed_with_non_utf32/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/range/same_high_surrogate/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/range/same_high_surrogate_with_quantifier/meta_model.py +8 -0
- dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/range/two_high_surrogates/meta_model.py +8 -0
- dev/test_data/intermediate/expected/class/empty/meta_model.py +6 -0
- dev/test_data/intermediate/expected/class/implementation_specific_method/meta_model.py +8 -0
- dev/test_data/intermediate/expected/class/inheritance/meta_model.py +41 -0
- dev/test_data/intermediate/expected/class/methods_with_contracts/meta_model.py +15 -0
- dev/test_data/intermediate/expected/class/only_method_no_property/meta_model.py +7 -0
- dev/test_data/intermediate/expected/class/only_property_no_method/meta_model.py +9 -0
- dev/test_data/intermediate/expected/constant/constant_set/of_enum/meta_model.py +12 -0
- dev/test_data/intermediate/expected/constant/constant_set/of_str/meta_model.py +4 -0
- dev/test_data/intermediate/expected/constant/constant_set/with_description/meta_model.py +6 -0
- dev/test_data/intermediate/expected/constant/constant_set/with_superset_of/meta_model.py +14 -0
- dev/test_data/intermediate/expected/constant/constant_str/only_value/meta_model.py +7 -0
- dev/test_data/intermediate/expected/constant/constant_str/with_description/meta_model.py +5 -0
- dev/test_data/intermediate/expected/documentation/docstring_with_special_characters_in_literal/meta_model.py +20 -0
- dev/test_data/intermediate/expected/documentation/docstring_with_special_characters_outside_literal/meta_model.py +20 -0
- dev/test_data/intermediate/expected/empty/meta_model.py +2 -0
- dev/test_data/intermediate/expected/enumeration/meta_model.py +9 -0
- dev/test_data/intermediate/expected/interface/basic/meta_model.py +14 -0
- dev/test_data/intermediate/expected/interface/empty/meta_model.py +7 -0
- dev/test_data/intermediate/expected/interface/inheritance/meta_model.py +27 -0
- dev/test_data/intermediate/expected/interface/method_signature/meta_model.py +10 -0
- dev/test_data/intermediate/expected/interface/only_constructor/meta_model.py +11 -0
- dev/test_data/intermediate/expected/method/non_mutating/implementation_specific/meta_model.py +12 -0
- dev/test_data/intermediate/expected/method/non_mutating/understood/meta_model.py +11 -0
- dev/test_data/intermediate/expected/type_annotation/atomic/meta_model.py +9 -0
- dev/test_data/intermediate/expected/type_annotation/subscripted/class/meta_model.py +13 -0
- dev/test_data/intermediate/expected/type_annotation/subscripted/primitive/meta_model.py +9 -0
- dev/test_data/intermediate/unexpected/constant_set/of_enum/enumeration_literals_in_subset_outside_of_superset/meta_model.py +20 -0
- dev/test_data/intermediate/unexpected/constant_set/of_enum/invalid_literal/meta_model.py +11 -0
- dev/test_data/intermediate/unexpected/constant_set/of_enum/mismatch_between_enumeration_and_literal/meta_model.py +30 -0
- dev/test_data/intermediate/unexpected/constant_set/of_enum/mismatch_in_enumerations_between_subset_and_superset/meta_model.py +21 -0
- dev/test_data/intermediate/unexpected/constant_set/of_str/literals_in_subset_outside_of_superset/meta_model.py +18 -0
- dev/test_data/intermediate/unexpected/constant_set/of_str/mismatch_between_type_annotation_and_literals/meta_model.py +10 -0
- dev/test_data/intermediate/unexpected/constant_set/of_str/superset_and_subset_mismatch_in_type/meta_model.py +12 -0
- dev/test_data/intermediate/unexpected/constraints/dangling_constraintref/meta_model.py +18 -0
- dev/test_data/intermediate/unexpected/constraints/duplicate_constraints/meta_model.py +20 -0
- dev/test_data/intermediate/unexpected/documentation/unexpected_documentation_elements/meta_model.py +34 -0
- dev/test_data/intermediate/unexpected/invariant/class_invariant_uses_re/meta_model.py +10 -0
- dev/test_data/intermediate/unexpected/invariant/invariant_of_constrained_primitive_uses_re/meta_model.py +7 -0
- dev/test_data/intermediate/unexpected/invariant/unexpected_argument_count_to_len/meta_model.py +20 -0
- dev/test_data/intermediate/unexpected/invariant/unhandled_built_in_function/meta_model.py +16 -0
- dev/test_data/intermediate/unexpected/method_definitions/non_constant_default/meta_model.py +7 -0
- dev/test_data/intermediate/unexpected/optional_constructor_arguments_wo_default/default_non_none/meta_model.py +16 -0
- dev/test_data/intermediate/unexpected/optional_constructor_arguments_wo_default/no_default/meta_model.py +16 -0
- dev/test_data/intermediate/unexpected/properties_and_constructor_arguments_do_not_match/after_inheritance/meta_model.py +58 -0
- dev/test_data/intermediate/unexpected/properties_and_constructor_arguments_do_not_match/type_missmatch/meta_model.py +9 -0
- dev/test_data/intermediate/unexpected/properties_and_constructor_arguments_do_not_match/within_class/meta_model.py +22 -0
- dev/test_data/jsonschema/test_main/regression_when_len_constraints_on_inherited_property/meta_model.py +28 -0
- dev/test_data/opcua/test_main/abstract_and_concrete_classes/meta_model.py +37 -0
- dev/test_data/opcua/test_main/classes_with_invariants/meta_model.py +21 -0
- dev/test_data/opcua/test_main/concrete_class_with_descendant/meta_model.py +27 -0
- dev/test_data/opcua/test_main/concrete_class_with_enum/meta_model.py +21 -0
- dev/test_data/opcua/test_main/concrete_class_with_list_of_instances/meta_model.py +21 -0
- dev/test_data/opcua/test_main/concrete_class_with_primitive_attributes/meta_model.py +41 -0
- dev/test_data/opcua/test_main/concrete_class_with_string/meta_model.py +13 -0
- dev/test_data/opcua/test_main/constrained_primitive/meta_model.py +20 -0
- dev/test_data/opcua/test_main/multiple_inheritance/meta_model.py +25 -0
- dev/test_data/parse/expected/constant/constant_set/of_enum/meta_model.py +12 -0
- dev/test_data/parse/expected/constant/constant_set/of_str/meta_model.py +4 -0
- dev/test_data/parse/expected/constant/constant_set/with_description/meta_model.py +6 -0
- dev/test_data/parse/expected/constant/constant_set/with_superset_of/meta_model.py +14 -0
- dev/test_data/parse/expected/constant/constant_str/only_value/meta_model.py +7 -0
- dev/test_data/parse/expected/constant/constant_str/with_description/meta_model.py +5 -0
- dev/test_data/parse/expected/enum/ok/meta_model.py +15 -0
- dev/test_data/parse/expected/implementation_specific_class/properties_and_methods_in_implementation_specific_class/meta_model.py +17 -0
- dev/test_data/parse/expected/inheritance/basic/meta_model.py +11 -0
- dev/test_data/parse/expected/inheritance/diamond/meta_model.py +26 -0
- dev/test_data/parse/expected/inheritance/inheritance_from_concrete_class/meta_model.py +10 -0
- dev/test_data/parse/expected/invariants/in_relation/meta_model.py +16 -0
- dev/test_data/parse/expected/method/arguments/meta_model.py +7 -0
- dev/test_data/parse/expected/method/basic/meta_model.py +7 -0
- dev/test_data/parse/expected/method/contracts/condition_as_keyword_argument/meta_model.py +8 -0
- dev/test_data/parse/expected/method/contracts/condition_as_positional_argument/meta_model.py +8 -0
- dev/test_data/parse/expected/method/contracts/description_as_keyword_argument/meta_model.py +8 -0
- dev/test_data/parse/expected/method/contracts/description_as_positional_argument/meta_model.py +8 -0
- dev/test_data/parse/expected/method/contracts/multiple_contracts_in_order/meta_model.py +17 -0
- dev/test_data/parse/expected/method/contracts/postcondition/basic/meta_model.py +10 -0
- dev/test_data/parse/expected/method/contracts/postcondition/snapshot/with_keyword_arguments/meta_model.py +9 -0
- dev/test_data/parse/expected/method/contracts/postcondition/snapshot/with_positional_arguments/meta_model.py +9 -0
- dev/test_data/parse/expected/method/default/meta_model.py +9 -0
- dev/test_data/parse/expected/method/description/meta_model.py +8 -0
- dev/test_data/parse/expected/method/is_implementation_specific/meta_model.py +8 -0
- dev/test_data/parse/expected/method/non_mutating/meta_model.py +11 -0
- dev/test_data/parse/expected/method/returns_none/meta_model.py +7 -0
- dev/test_data/parse/expected/method/returns_something/meta_model.py +7 -0
- dev/test_data/parse/expected/single_class/description/meta_model.py +12 -0
- dev/test_data/parse/expected/single_class/empty/meta_model.py +6 -0
- dev/test_data/parse/expected/single_class/property/description/meta_model.py +14 -0
- dev/test_data/parse/expected/single_class/property/mandatory/meta_model.py +6 -0
- dev/test_data/parse/expected/single_class/property/optional/meta_model.py +6 -0
- dev/test_data/parse/expected/single_class/property/recursion_to_entity/meta_model.py +6 -0
- dev/test_data/parse/unexpected/class_decorators/non_name_decorator/meta_model.py +7 -0
- dev/test_data/parse/unexpected/class_decorators/unknown_decorator/meta_model.py +7 -0
- dev/test_data/parse/unexpected/class_definitions/is_abstract_and_implementation_specific/meta_model.py +8 -0
- dev/test_data/parse/unexpected/class_definitions/unexpected_docstring_before_a_method/meta_model.py +11 -0
- dev/test_data/parse/unexpected/class_definitions/unexpected_docstring_for_a_pass/meta_model.py +9 -0
- dev/test_data/parse/unexpected/class_definitions/unexpected_double_description_for_a_property/meta_model.py +10 -0
- dev/test_data/parse/unexpected/class_inheritances/inheriting_from_implementation_specific_parent/meta_model.py +20 -0
- dev/test_data/parse/unexpected/class_inheritances/non_name_super_class/meta_model.py +6 -0
- dev/test_data/parse/unexpected/enum/expression_as_assignment_value/meta_model.py +6 -0
- dev/test_data/parse/unexpected/enum/non_assignment/meta_model.py +8 -0
- dev/test_data/parse/unexpected/enum/non_string_literal/meta_model.py +6 -0
- dev/test_data/parse/unexpected/enum/unexpected_inheritance/meta_model.py +6 -0
- dev/test_data/parse/unexpected/method_contracts/contract/non_lambda_condition/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_contracts/contract/non_string_literal_description/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_contracts/contract/without_any_arguments/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_contracts/contract/without_condition/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_contracts/postcondition/OLD_in_postcondition_without_snapshot/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_contracts/postcondition/argument_missing_in_function/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_contracts/precondition/argument_missing_in_function/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_contracts/snapshot/argument_missing_in_function/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_contracts/snapshot/capture_not_a_lambda/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_contracts/snapshot/invalid_name/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_contracts/snapshot/name_not_a_string_literal/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_contracts/snapshot/without_a_capture/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_contracts/snapshot/without_a_name/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_decorators/non_mutating/non_mutating_constructor/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_decorators/non_mutating/non_mutating_verification_function/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_decorators/non_name_decorator/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_decorators/unknown_call_decorator/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_decorators/unknown_name_decorator/meta_model.py +8 -0
- dev/test_data/parse/unexpected/method_definitions/argument_with_final/meta_model.py +7 -0
- dev/test_data/parse/unexpected/method_definitions/argument_without_a_type_annotation/meta_model.py +7 -0
- dev/test_data/parse/unexpected/method_definitions/default_for_self/meta_model.py +7 -0
- dev/test_data/parse/unexpected/method_definitions/dunder/meta_model.py +7 -0
- dev/test_data/parse/unexpected/method_definitions/init_with_return_type/meta_model.py +7 -0
- dev/test_data/parse/unexpected/method_definitions/with_keyword_only_arguments/meta_model.py +7 -0
- dev/test_data/parse/unexpected/method_definitions/with_positional_arguments/meta_model.py +7 -0
- dev/test_data/parse/unexpected/method_definitions/with_type_annotation_for_self/meta_model.py +7 -0
- dev/test_data/parse/unexpected/method_definitions/with_variable_arguments/meta_model.py +7 -0
- dev/test_data/parse/unexpected/method_definitions/with_variable_keyword_arguments/meta_model.py +7 -0
- dev/test_data/parse/unexpected/method_definitions/without_arguments/meta_model.py +7 -0
- dev/test_data/parse/unexpected/method_definitions/without_self/meta_model.py +7 -0
- dev/test_data/parse/unexpected/method_definitions/without_type_annotation_for_result/meta_model.py +7 -0
- dev/test_data/parse/unexpected/property_definitions/final_without_subscript/meta_model.py +6 -0
- dev/test_data/parse/unexpected/property_definitions/nested_final/meta_model.py +6 -0
- dev/test_data/parse/unexpected/property_definitions/non_simple/meta_model.py +6 -0
- dev/test_data/parse/unexpected/property_definitions/unexpected_assignment/meta_model.py +6 -0
- dev/test_data/parse/unexpected/property_definitions/unexpected_non_name_property/meta_model.py +6 -0
- dev/test_data/parse/unexpected/property_definitions/without_type_annotation/meta_model.py +6 -0
- dev/test_data/parse/unexpected/symbol_table/constant_set_with_a_non_set_subset/meta_model.py +6 -0
- dev/test_data/parse/unexpected/symbol_table/dangling_inheritance/meta_model.py +6 -0
- dev/test_data/parse/unexpected/symbol_table/dangling_reference_in_type_annotation_of_a_property/meta_model.py +6 -0
- dev/test_data/parse/unexpected/symbol_table/dangling_reference_in_type_annotation_of_an_argument/meta_model.py +7 -0
- dev/test_data/parse/unexpected/symbol_table/dangling_reference_in_type_annotation_of_constant_set/meta_model.py +6 -0
- dev/test_data/parse/unexpected/symbol_table/dangling_subset_in_constant_set/meta_model.py +4 -0
- dev/test_data/parse/unexpected/symbol_table/inheritance_from_non_class/meta_model.py +10 -0
- dev/test_data/parse_retree/expected/character_set/common_escaping/source.py +1 -0
- dev/test_data/parse_retree/expected/character_set/complementing/double_caret/source.py +1 -0
- dev/test_data/parse_retree/expected/character_set/complementing/multiple_ranges/source.py +1 -0
- dev/test_data/parse_retree/expected/character_set/complementing/suffix_dash/source.py +1 -0
- dev/test_data/parse_retree/expected/character_set/escape_first_caret/source.py +1 -0
- dev/test_data/parse_retree/expected/character_set/literals_which_need_no_escaping_in_characters_set_but_need_escaping_outside/source.py +1 -0
- dev/test_data/parse_retree/expected/character_set/multiple_ranges/source.py +1 -0
- dev/test_data/parse_retree/expected/character_set/single_literal/source.py +1 -0
- dev/test_data/parse_retree/expected/character_set/single_range/source.py +1 -0
- dev/test_data/parse_retree/expected/character_set/unescaped_dash/only_dash/source.py +1 -0
- dev/test_data/parse_retree/expected/character_set/unescaped_dash/prefix_dash/source.py +1 -0
- dev/test_data/parse_retree/expected/character_set/unescaped_dash/suffix_dash/source.py +1 -0
- dev/test_data/parse_retree/expected/dot/source.py +1 -0
- dev/test_data/parse_retree/expected/empty/group/source.py +1 -0
- dev/test_data/parse_retree/expected/empty/group_in_a_group/source.py +1 -0
- dev/test_data/parse_retree/expected/empty/group_of_union_of_empty_concatenations/source.py +1 -0
- dev/test_data/parse_retree/expected/empty/regex/source.py +1 -0
- dev/test_data/parse_retree/expected/empty/union_of_empty_concatenations/source.py +1 -0
- dev/test_data/parse_retree/expected/escaped_literals/source.py +1 -0
- dev/test_data/parse_retree/expected/formatted_value/at_the_beginning/source.py +1 -0
- dev/test_data/parse_retree/expected/formatted_value/at_the_end/source.py +1 -0
- dev/test_data/parse_retree/expected/formatted_value/in_the_middle/source.py +1 -0
- dev/test_data/parse_retree/expected/formatted_value/single_formatted_value/source.py +1 -0
- dev/test_data/parse_retree/expected/literal/source.py +1 -0
- dev/test_data/parse_retree/expected/quantifier/greedy/at_least_3/source.py +1 -0
- dev/test_data/parse_retree/expected/quantifier/greedy/at_least_one/source.py +1 -0
- dev/test_data/parse_retree/expected/quantifier/greedy/at_most_3/source.py +1 -0
- dev/test_data/parse_retree/expected/quantifier/greedy/exactly_3/source.py +1 -0
- dev/test_data/parse_retree/expected/quantifier/greedy/maybe/source.py +1 -0
- dev/test_data/parse_retree/expected/quantifier/greedy/zero_or_more/source.py +1 -0
- dev/test_data/parse_retree/expected/quantifier/non_greedy/at_least_3/source.py +1 -0
- dev/test_data/parse_retree/expected/quantifier/non_greedy/at_least_one/source.py +1 -0
- dev/test_data/parse_retree/expected/quantifier/non_greedy/at_most_3/source.py +1 -0
- dev/test_data/parse_retree/expected/quantifier/non_greedy/exactly_3/source.py +1 -0
- dev/test_data/parse_retree/expected/quantifier/non_greedy/maybe/source.py +1 -0
- dev/test_data/parse_retree/expected/quantifier/non_greedy/zero_or_more/source.py +1 -0
- dev/test_data/parse_retree/expected/quantifier/on_a_character_set/source.py +1 -0
- dev/test_data/parse_retree/expected/quantifier/on_a_formatted_value/source.py +1 -0
- dev/test_data/parse_retree/expected/quantifier/on_a_group/source.py +1 -0
- dev/test_data/parse_retree/expected/quantifier/on_a_literal/source.py +1 -0
- dev/test_data/parse_retree/expected/start_and_stop_symbols/double_end_symbol/source.py +1 -0
- dev/test_data/parse_retree/expected/start_and_stop_symbols/double_start_symbol/source.py +1 -0
- dev/test_data/parse_retree/expected/start_and_stop_symbols/end_symbol_in_the_middle/source.py +1 -0
- dev/test_data/parse_retree/expected/start_and_stop_symbols/only_start_symbol/source.py +1 -0
- dev/test_data/parse_retree/expected/start_and_stop_symbols/only_stop_symbol/source.py +1 -0
- dev/test_data/parse_retree/expected/start_and_stop_symbols/start_symbol_at_the_beginning/source.py +1 -0
- dev/test_data/parse_retree/expected/start_and_stop_symbols/start_symbol_in_the_middle/source.py +1 -0
- dev/test_data/parse_retree/expected/start_and_stop_symbols/stop_symbol_at_the_end/source.py +1 -0
- dev/test_data/parse_retree/expected/union/of_character_sets/source.py +1 -0
- dev/test_data/parse_retree/expected/union/of_groups/source.py +1 -0
- dev/test_data/parse_retree/expected/union/of_string_literals/source.py +1 -0
- dev/test_data/parse_retree/expected/union/within_group/source.py +1 -0
- dev/test_data/parse_retree/expected/whitespace/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/Uxxxxxxxx_out_of_range/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/only_backslash/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/short_Uxxxxxxxx/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/short_uxxxx/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/short_x/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/unexpected_escaping/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/unhandled/digit/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/unhandled/not_digit/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/unhandled/not_whitespace/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/unhandled/not_word/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/unhandled/whitespace/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/unhandled/word/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/range_character/Uxxxxxxxx_out_of_range/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/range_character/only_backslash/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/range_character/short_Uxxxxxxxx/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/range_character/short_uxxxx/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/range_character/short_x/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/range_character/unexpected_escaping/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/range_character/unhandled/digit/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/range_character/unhandled/not_digit/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/range_character/unhandled/not_whitespace/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/range_character/unhandled/not_word/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/range_character/unhandled/whitespace/source.py +1 -0
- dev/test_data/parse_retree/unexpected/improper_escaping/range_character/unhandled/word/source.py +1 -0
- dev/test_data/parse_retree/unexpected/invalid_character_range/source.py +1 -0
- dev/test_data/parse_retree/unexpected/invalid_quantifier/at_least_x/source.py +1 -0
- dev/test_data/parse_retree/unexpected/invalid_quantifier/between_3_and_x/source.py +1 -0
- dev/test_data/parse_retree/unexpected/invalid_quantifier/exactly_x/source.py +1 -0
- dev/test_data/parse_retree/unexpected/unhandled_group_directives/source.py +1 -0
- dev/test_data/parse_retree/unexpected/unterminated/character_set/source.py +1 -0
- dev/test_data/parse_retree/unexpected/unterminated/group/source.py +1 -0
- dev/test_data/parse_retree/unexpected/unterminated/group_of_union_of_empty_concatenations/source.py +1 -0
- dev/test_data/parse_retree/unexpected/unterminated/quantifier/source.py +1 -0
- dev/test_data/parse_retree/unexpected/unterminated/quantifier_with_comma/source.py +1 -0
- dev/test_data/parse_retree/unexpected/unterminated/quantifier_with_number_and_comma/source.py +1 -0
- dev/test_data/proto/test_main/expected/abstract_and_concrete_classes/meta_model.py +37 -0
- dev/test_data/proto/test_main/expected/concrete_class_with_descendants/meta_model.py +30 -0
- dev/test_data/proto/test_main/expected/concrete_class_with_enum/meta_model.py +21 -0
- dev/test_data/proto/test_main/expected/concrete_class_with_list_of_instances/meta_model.py +21 -0
- dev/test_data/proto/test_main/expected/concrete_class_with_primitive_attributes/meta_model.py +41 -0
- dev/test_data/python_protobuf/test_main/abstract_and_concrete_classes/expected_output/pbization.py +532 -0
- dev/test_data/python_protobuf/test_main/abstract_and_concrete_classes/meta_model.py +37 -0
- dev/test_data/python_protobuf/test_main/concrete_class_with_descendant/expected_output/pbization.py +527 -0
- dev/test_data/python_protobuf/test_main/concrete_class_with_descendant/meta_model.py +27 -0
- dev/test_data/python_protobuf/test_main/concrete_class_with_enum/expected_output/pbization.py +290 -0
- dev/test_data/python_protobuf/test_main/concrete_class_with_enum/meta_model.py +21 -0
- dev/test_data/python_protobuf/test_main/concrete_class_with_list_of_instances/expected_output/pbization.py +328 -0
- dev/test_data/python_protobuf/test_main/concrete_class_with_list_of_instances/meta_model.py +23 -0
- dev/test_data/python_protobuf/test_main/concrete_class_with_primitive_attributes/expected_output/pbization.py +274 -0
- dev/test_data/python_protobuf/test_main/concrete_class_with_primitive_attributes/meta_model.py +41 -0
- dev/test_data/rdf_shacl/test_main/expected/regression_when_lang_string_class_is_missing/meta_model.py +29 -0
- dev/test_data/rdf_shacl/test_main/expected/regression_when_len_constraints_on_inherited_property/meta_model.py +27 -0
- dev/test_data/rdf_shacl/test_main/unexpected/regression_len_constraint_on_class_property/meta_model.py +61 -0
- dev/test_data/real_meta_models/aas_core_meta.v3.py +5721 -0
- dev/test_data/smoke/test_main/unexpected/infer_for_schema_error/meta_model.py +12 -0
- dev/test_data/smoke/test_main/unexpected/intermediate_error/meta_model.py +18 -0
- dev/test_data/smoke/test_main/unexpected/parse_error/meta_model.py +5 -0
- dev/test_data/smoke/test_main/unexpected/pattern_verification_unparsable_regex/direct_match/meta_model.py +8 -0
- dev/test_data/smoke/test_main/unexpected/type_error/meta_model.py +18 -0
- dev/tests/__init__.py +1 -0
- dev/tests/common.py +197 -0
- dev/tests/cpp/__init__.py +0 -0
- dev/tests/cpp/test_common.py +32 -0
- dev/tests/cpp/test_main.py +144 -0
- dev/tests/cpp/test_pattern.py +188 -0
- dev/tests/cpp/test_verification.py +189 -0
- dev/tests/cpp/test_yielding.py +225 -0
- dev/tests/csharp/__init__.py +0 -0
- dev/tests/csharp/live_test_main.py +109 -0
- dev/tests/csharp/test_common.py +28 -0
- dev/tests/csharp/test_description.py +684 -0
- dev/tests/csharp/test_main.py +129 -0
- dev/tests/csharp/test_structure.py +93 -0
- dev/tests/csharp/test_verification.py +82 -0
- dev/tests/description.py +29 -0
- dev/tests/golang/__init__.py +0 -0
- dev/tests/golang/test_common.py +78 -0
- dev/tests/golang/test_main.py +128 -0
- dev/tests/infer_for_schema/__init__.py +0 -0
- dev/tests/infer_for_schema/common.py +47 -0
- dev/tests/infer_for_schema/test_len_on_properties.py +955 -0
- dev/tests/infer_for_schema/test_len_on_self.py +580 -0
- dev/tests/infer_for_schema/test_patterns_on_properties.py +686 -0
- dev/tests/infer_for_schema/test_patterns_on_self.py +258 -0
- dev/tests/infer_for_schema/test_property_in_set_of_enumeration_literals.py +600 -0
- dev/tests/infer_for_schema/test_property_in_set_of_primitives.py +549 -0
- dev/tests/intermediate/__init__.py +0 -0
- dev/tests/intermediate/test_constructor.py +719 -0
- dev/tests/intermediate/test_hierarchy.py +221 -0
- dev/tests/intermediate/test_revm.py +134 -0
- dev/tests/intermediate/test_translate.py +337 -0
- dev/tests/intermediate/test_type_inference.py +333 -0
- dev/tests/intermediate/test_types.py +169 -0
- dev/tests/java/__init__.py +0 -0
- dev/tests/java/test_common.py +20 -0
- dev/tests/java/test_description.py +128 -0
- dev/tests/java/test_main.py +234 -0
- dev/tests/jsonld_context/test_main.py +79 -0
- dev/tests/opcua/__init__.py +3 -0
- dev/tests/opcua/test_main.py +110 -0
- dev/tests/our_jsonschema/__init__.py +3 -0
- dev/tests/our_jsonschema/test_main.py +232 -0
- dev/tests/parse/__init__.py +0 -0
- dev/tests/parse/test_parse.py +503 -0
- dev/tests/parse/test_retree.py +272 -0
- dev/tests/proto/__init__.py +0 -0
- dev/tests/proto/test_main.py +112 -0
- dev/tests/python/__init__.py +0 -0
- dev/tests/python/test_common.py +124 -0
- dev/tests/python/test_main.py +126 -0
- dev/tests/python/test_xml_playground.py +254 -0
- dev/tests/python_protobuf/__init__.py +0 -0
- dev/tests/python_protobuf/test_main.py +111 -0
- dev/tests/rdf_shacl/__init__.py +0 -0
- dev/tests/rdf_shacl/test_common.py +32 -0
- dev/tests/rdf_shacl/test_description.py +223 -0
- dev/tests/rdf_shacl/test_main.py +194 -0
- dev/tests/smoke/__init__.py +0 -0
- dev/tests/smoke/test_main.py +83 -0
- dev/tests/test_common.py +94 -0
- dev/tests/typescript/__init__.py +0 -0
- dev/tests/typescript/test_common.py +108 -0
- dev/tests/typescript/test_main.py +125 -0
- dev/tests/xsd/__init__.py +0 -0
- dev/tests/xsd/test_main.py +227 -0
- dev/tests/yielding/__init__.py +0 -0
- dev/tests/yielding/test_linear.py +558 -0
|
@@ -0,0 +1,2901 @@
|
|
|
1
|
+
"""Provide types of the intermediate representation."""
|
|
2
|
+
import abc
|
|
3
|
+
import enum
|
|
4
|
+
import pathlib
|
|
5
|
+
from typing import (
|
|
6
|
+
Sequence,
|
|
7
|
+
Optional,
|
|
8
|
+
Union,
|
|
9
|
+
TypeVar,
|
|
10
|
+
Mapping,
|
|
11
|
+
MutableMapping,
|
|
12
|
+
Final,
|
|
13
|
+
FrozenSet,
|
|
14
|
+
Set,
|
|
15
|
+
OrderedDict,
|
|
16
|
+
Type,
|
|
17
|
+
get_args,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
import docutils.nodes
|
|
21
|
+
from icontract import require, invariant, ensure, DBC
|
|
22
|
+
|
|
23
|
+
from aas_core_codegen import parse
|
|
24
|
+
from aas_core_codegen.common import (
|
|
25
|
+
Identifier,
|
|
26
|
+
assert_never,
|
|
27
|
+
assert_union_of_descendants_exhaustive,
|
|
28
|
+
assert_union_without_excluded,
|
|
29
|
+
Stripped,
|
|
30
|
+
)
|
|
31
|
+
from aas_core_codegen.intermediate import construction
|
|
32
|
+
from aas_core_codegen.parse import tree as parse_tree
|
|
33
|
+
|
|
34
|
+
_MODULE_NAME = pathlib.Path(__file__).parent.name
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class PrimitiveType(enum.Enum):
|
|
38
|
+
"""List primitive types."""
|
|
39
|
+
|
|
40
|
+
BOOL = "bool"
|
|
41
|
+
INT = "int"
|
|
42
|
+
FLOAT = "float"
|
|
43
|
+
STR = "str"
|
|
44
|
+
BYTEARRAY = "bytearray"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
assert sorted(literal.value for literal in PrimitiveType) == sorted(
|
|
48
|
+
parse.PRIMITIVE_TYPES
|
|
49
|
+
), "All primitive types specified in the intermediate layer"
|
|
50
|
+
|
|
51
|
+
STR_TO_PRIMITIVE_TYPE = {
|
|
52
|
+
literal.value: literal for literal in PrimitiveType
|
|
53
|
+
} # type: Mapping[str, PrimitiveType]
|
|
54
|
+
|
|
55
|
+
# fmt: off
|
|
56
|
+
PRIMITIVE_TYPE_TO_PYTHON_TYPE: Mapping[
|
|
57
|
+
PrimitiveType,
|
|
58
|
+
Union[Type[bool], Type[int], Type[float], Type[str], Type[bytearray]]
|
|
59
|
+
] = {
|
|
60
|
+
PrimitiveType.BOOL: bool,
|
|
61
|
+
PrimitiveType.INT : int,
|
|
62
|
+
PrimitiveType.FLOAT: float,
|
|
63
|
+
PrimitiveType.STR: str,
|
|
64
|
+
PrimitiveType.BYTEARRAY: bytearray,
|
|
65
|
+
}
|
|
66
|
+
assert all(
|
|
67
|
+
primitive_type in PRIMITIVE_TYPE_TO_PYTHON_TYPE
|
|
68
|
+
for primitive_type in PrimitiveType
|
|
69
|
+
)
|
|
70
|
+
# fmt: on
|
|
71
|
+
|
|
72
|
+
# fmt: off
|
|
73
|
+
PYTHON_TYPE_TO_PRIMITIVE_TYPE: Mapping[
|
|
74
|
+
Union[Type[bool], Type[int], Type[float], Type[str], Type[bytearray]],
|
|
75
|
+
PrimitiveType
|
|
76
|
+
] = {
|
|
77
|
+
bool: PrimitiveType.BOOL,
|
|
78
|
+
int: PrimitiveType.INT,
|
|
79
|
+
float: PrimitiveType.FLOAT,
|
|
80
|
+
str: PrimitiveType.STR,
|
|
81
|
+
bytearray: PrimitiveType.BYTEARRAY,
|
|
82
|
+
}
|
|
83
|
+
assert (
|
|
84
|
+
sorted(key.__name__ for key in PYTHON_TYPE_TO_PRIMITIVE_TYPE) ==
|
|
85
|
+
sorted(value.__name__ for value in PRIMITIVE_TYPE_TO_PYTHON_TYPE.values())
|
|
86
|
+
)
|
|
87
|
+
# fmt: on
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class TypeAnnotation(DBC):
|
|
91
|
+
"""Represent a general type annotation."""
|
|
92
|
+
|
|
93
|
+
#: Relation to the parse stage
|
|
94
|
+
parsed: Final[parse.TypeAnnotation]
|
|
95
|
+
|
|
96
|
+
def __init__(self, parsed: parse.TypeAnnotation) -> None:
|
|
97
|
+
"""Initialize with the given values."""
|
|
98
|
+
self.parsed = parsed
|
|
99
|
+
|
|
100
|
+
@abc.abstractmethod
|
|
101
|
+
def __str__(self) -> str:
|
|
102
|
+
# Signal that this class is a purely abstract one
|
|
103
|
+
raise NotImplementedError()
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class PrimitiveTypeAnnotation(TypeAnnotation):
|
|
107
|
+
"""Represent a primitive type such as ``int``."""
|
|
108
|
+
|
|
109
|
+
def __init__(self, a_type: PrimitiveType, parsed: parse.TypeAnnotation) -> None:
|
|
110
|
+
"""Initialize with the given values."""
|
|
111
|
+
TypeAnnotation.__init__(self, parsed=parsed)
|
|
112
|
+
self.a_type = a_type
|
|
113
|
+
|
|
114
|
+
def __str__(self) -> str:
|
|
115
|
+
return str(self.a_type.value)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class OurTypeAnnotation(TypeAnnotation):
|
|
119
|
+
"""
|
|
120
|
+
Represent an atomic annotation defined by our type in the meta-model.
|
|
121
|
+
|
|
122
|
+
For example, ``Asset``.
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
def __init__(self, our_type: "OurType", parsed: parse.TypeAnnotation) -> None:
|
|
126
|
+
"""Initialize with the given values."""
|
|
127
|
+
TypeAnnotation.__init__(self, parsed=parsed)
|
|
128
|
+
self.our_type = our_type
|
|
129
|
+
|
|
130
|
+
def __str__(self) -> str:
|
|
131
|
+
return self.our_type.name
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class ListTypeAnnotation(TypeAnnotation):
|
|
135
|
+
"""Represent a type annotation involving a ``List[...]``."""
|
|
136
|
+
|
|
137
|
+
def __init__(self, items: "TypeAnnotationUnion", parsed: parse.TypeAnnotation):
|
|
138
|
+
TypeAnnotation.__init__(self, parsed=parsed)
|
|
139
|
+
|
|
140
|
+
self.items = items
|
|
141
|
+
|
|
142
|
+
def __str__(self) -> str:
|
|
143
|
+
return f"List[{self.items}]"
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
# NOTE (mristin, 2021-11-19):
|
|
147
|
+
# We do not support other generic types except for ``List``. In the future we might
|
|
148
|
+
# add support for ``Set``, ``MutableMapping`` *etc.*
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class OptionalTypeAnnotation(TypeAnnotation):
|
|
152
|
+
"""Represent a type annotation involving an ``Optional[...]``."""
|
|
153
|
+
|
|
154
|
+
def __init__(self, value: "TypeAnnotationUnion", parsed: parse.TypeAnnotation):
|
|
155
|
+
TypeAnnotation.__init__(self, parsed=parsed)
|
|
156
|
+
|
|
157
|
+
self.value = value
|
|
158
|
+
|
|
159
|
+
def __str__(self) -> str:
|
|
160
|
+
return f"Optional[{self.value}]"
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
TypeAnnotationUnion = Union[
|
|
164
|
+
PrimitiveTypeAnnotation,
|
|
165
|
+
OurTypeAnnotation,
|
|
166
|
+
ListTypeAnnotation,
|
|
167
|
+
OptionalTypeAnnotation,
|
|
168
|
+
]
|
|
169
|
+
|
|
170
|
+
assert_union_of_descendants_exhaustive(
|
|
171
|
+
union=TypeAnnotationUnion, base_class=TypeAnnotation
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
TypeAnnotationUnionAsTuple = (
|
|
175
|
+
PrimitiveTypeAnnotation,
|
|
176
|
+
OurTypeAnnotation,
|
|
177
|
+
ListTypeAnnotation,
|
|
178
|
+
OptionalTypeAnnotation,
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
assert TypeAnnotationUnionAsTuple == get_args(TypeAnnotationUnion)
|
|
182
|
+
|
|
183
|
+
TypeAnnotationExceptOptional = Union[
|
|
184
|
+
PrimitiveTypeAnnotation,
|
|
185
|
+
OurTypeAnnotation,
|
|
186
|
+
ListTypeAnnotation,
|
|
187
|
+
]
|
|
188
|
+
|
|
189
|
+
assert_union_without_excluded(
|
|
190
|
+
original_union=TypeAnnotationUnion,
|
|
191
|
+
subset_union=TypeAnnotationExceptOptional,
|
|
192
|
+
excluded=[OptionalTypeAnnotation],
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
TypeAnnotationExceptOptionalAsTuple = (
|
|
196
|
+
PrimitiveTypeAnnotation,
|
|
197
|
+
OurTypeAnnotation,
|
|
198
|
+
ListTypeAnnotation,
|
|
199
|
+
)
|
|
200
|
+
assert TypeAnnotationExceptOptionalAsTuple == get_args(TypeAnnotationExceptOptional)
|
|
201
|
+
|
|
202
|
+
AtomicTypeAnnotation = Union[PrimitiveTypeAnnotation, OurTypeAnnotation]
|
|
203
|
+
|
|
204
|
+
assert_union_without_excluded(
|
|
205
|
+
original_union=TypeAnnotationUnion,
|
|
206
|
+
subset_union=AtomicTypeAnnotation,
|
|
207
|
+
excluded=[ListTypeAnnotation, OptionalTypeAnnotation],
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def type_annotations_equal(
|
|
212
|
+
that: TypeAnnotationUnion, other: TypeAnnotationUnion
|
|
213
|
+
) -> bool:
|
|
214
|
+
"""
|
|
215
|
+
Compare two type annotations for equality.
|
|
216
|
+
|
|
217
|
+
Two type annotations are equal if they describe the same type.
|
|
218
|
+
"""
|
|
219
|
+
if type(that) is not type(other):
|
|
220
|
+
return False
|
|
221
|
+
|
|
222
|
+
if isinstance(that, PrimitiveTypeAnnotation):
|
|
223
|
+
assert isinstance(other, PrimitiveTypeAnnotation)
|
|
224
|
+
return that.a_type == other.a_type
|
|
225
|
+
|
|
226
|
+
elif isinstance(that, OurTypeAnnotation):
|
|
227
|
+
assert isinstance(other, OurTypeAnnotation)
|
|
228
|
+
return that.our_type == other.our_type
|
|
229
|
+
|
|
230
|
+
elif isinstance(that, ListTypeAnnotation):
|
|
231
|
+
assert isinstance(other, ListTypeAnnotation)
|
|
232
|
+
return type_annotations_equal(that.items, other.items)
|
|
233
|
+
|
|
234
|
+
elif isinstance(that, OptionalTypeAnnotation):
|
|
235
|
+
assert isinstance(other, OptionalTypeAnnotation)
|
|
236
|
+
return type_annotations_equal(that.value, other.value)
|
|
237
|
+
|
|
238
|
+
else:
|
|
239
|
+
assert_never(that)
|
|
240
|
+
|
|
241
|
+
raise AssertionError("Should not have gotten here")
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def beneath_optional(
|
|
245
|
+
type_annotation: TypeAnnotationUnion,
|
|
246
|
+
) -> TypeAnnotationExceptOptional:
|
|
247
|
+
"""Descend below ``Optional[...]`` to the underlying type."""
|
|
248
|
+
type_anno = type_annotation
|
|
249
|
+
while isinstance(type_anno, OptionalTypeAnnotation):
|
|
250
|
+
type_anno = type_anno.value
|
|
251
|
+
|
|
252
|
+
assert not isinstance(type_anno, OptionalTypeAnnotation)
|
|
253
|
+
|
|
254
|
+
return type_anno
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
# region Descriptions
|
|
258
|
+
|
|
259
|
+
# NOTE (mristin, 2022-03-18):
|
|
260
|
+
# We take C# documentation comments as an orientation for the structure of the
|
|
261
|
+
# descriptions.
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def find_first_field_list(
|
|
265
|
+
element: docutils.nodes.Element,
|
|
266
|
+
) -> Optional[docutils.nodes.field_list]:
|
|
267
|
+
"""Find the first field list beneath the element or return None."""
|
|
268
|
+
return next(element.findall(condition=docutils.nodes.field_list), None)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class SummaryRemarksDescription(DBC):
|
|
272
|
+
"""Represent a description with a summary and remarks."""
|
|
273
|
+
|
|
274
|
+
#: Summary as the first line of the docstring
|
|
275
|
+
summary: Final[docutils.nodes.paragraph]
|
|
276
|
+
|
|
277
|
+
#: List of remarks following the summary in the docstring
|
|
278
|
+
remarks: Final[Sequence[docutils.nodes.Element]]
|
|
279
|
+
|
|
280
|
+
#: Original parsed description
|
|
281
|
+
parsed: Final[parse.Description]
|
|
282
|
+
|
|
283
|
+
# fmt: off
|
|
284
|
+
@require(
|
|
285
|
+
lambda summary:
|
|
286
|
+
find_first_field_list(summary) is None,
|
|
287
|
+
"Summary expected without field lists"
|
|
288
|
+
)
|
|
289
|
+
@require(
|
|
290
|
+
lambda remarks:
|
|
291
|
+
all(
|
|
292
|
+
find_first_field_list(remark) is None
|
|
293
|
+
for remark in remarks
|
|
294
|
+
),
|
|
295
|
+
"Remarks expected without field lists"
|
|
296
|
+
)
|
|
297
|
+
# fmt: on
|
|
298
|
+
def __init__(
|
|
299
|
+
self,
|
|
300
|
+
summary: docutils.nodes.paragraph,
|
|
301
|
+
remarks: Sequence[docutils.nodes.Element],
|
|
302
|
+
parsed: parse.Description,
|
|
303
|
+
) -> None:
|
|
304
|
+
"""Initialize with the given values."""
|
|
305
|
+
self.summary = summary
|
|
306
|
+
self.remarks = remarks
|
|
307
|
+
self.parsed = parsed
|
|
308
|
+
|
|
309
|
+
@abc.abstractmethod
|
|
310
|
+
def __repr__(self) -> str:
|
|
311
|
+
"""Represent the instance as a string for easier debugging."""
|
|
312
|
+
raise NotImplementedError()
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
# noinspection PyAbstractClass
|
|
316
|
+
class SummaryRemarksConstraintsDescription(SummaryRemarksDescription):
|
|
317
|
+
"""Represent a description with summary, remarks and constraints blocks."""
|
|
318
|
+
|
|
319
|
+
#: Map constraint documentation elements by their identifiers
|
|
320
|
+
constraints_by_identifier: Final[OrderedDict[str, docutils.nodes.field_body]]
|
|
321
|
+
|
|
322
|
+
# fmt: off
|
|
323
|
+
@require(
|
|
324
|
+
lambda constraints_by_identifier:
|
|
325
|
+
all(
|
|
326
|
+
find_first_field_list(body) is None
|
|
327
|
+
for body in constraints_by_identifier.values()
|
|
328
|
+
),
|
|
329
|
+
"Constraint bodies expected without field lists"
|
|
330
|
+
)
|
|
331
|
+
# fmt: on
|
|
332
|
+
def __init__(
|
|
333
|
+
self,
|
|
334
|
+
summary: docutils.nodes.paragraph,
|
|
335
|
+
remarks: Sequence[docutils.nodes.Element],
|
|
336
|
+
constraints_by_identifier: OrderedDict[str, docutils.nodes.field_body],
|
|
337
|
+
parsed: parse.Description,
|
|
338
|
+
) -> None:
|
|
339
|
+
"""Initialize with the given values."""
|
|
340
|
+
SummaryRemarksDescription.__init__(
|
|
341
|
+
self, summary=summary, remarks=remarks, parsed=parsed
|
|
342
|
+
)
|
|
343
|
+
self.constraints_by_identifier = constraints_by_identifier
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
class DescriptionOfMetaModel(SummaryRemarksConstraintsDescription):
|
|
347
|
+
"""Represent a description of a meta-model."""
|
|
348
|
+
|
|
349
|
+
def __repr__(self) -> str:
|
|
350
|
+
"""Represent the instance as a string for easier debugging."""
|
|
351
|
+
return f"<{_MODULE_NAME}.{self.__class__.__name__} at 0x{id(self):x}>"
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
class DescriptionOfOurType(SummaryRemarksConstraintsDescription):
|
|
355
|
+
"""Represent a description of our type."""
|
|
356
|
+
|
|
357
|
+
def __repr__(self) -> str:
|
|
358
|
+
"""Represent the instance as a string for easier debugging."""
|
|
359
|
+
return f"<{_MODULE_NAME}.{self.__class__.__name__} at 0x{id(self):x}>"
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
class DescriptionOfProperty(SummaryRemarksConstraintsDescription):
|
|
363
|
+
"""Represent a documentation of a property."""
|
|
364
|
+
|
|
365
|
+
def __repr__(self) -> str:
|
|
366
|
+
"""Represent the instance as a string for easier debugging."""
|
|
367
|
+
return f"<{_MODULE_NAME}.{self.__class__.__name__} at 0x{id(self):x}>"
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
class DescriptionOfEnumerationLiteral(SummaryRemarksDescription):
|
|
371
|
+
"""Represent a documentation of an enumeration literal."""
|
|
372
|
+
|
|
373
|
+
def __repr__(self) -> str:
|
|
374
|
+
"""Represent the instance as a string for easier debugging."""
|
|
375
|
+
return f"<{_MODULE_NAME}.{self.__class__.__name__} at 0x{id(self):x}>"
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
class DescriptionOfSignature(SummaryRemarksDescription):
|
|
379
|
+
"""Represent a documentation of a method or a function signature."""
|
|
380
|
+
|
|
381
|
+
#: Map argument documentation by the argument names
|
|
382
|
+
arguments_by_name: Final[OrderedDict[Identifier, docutils.nodes.field_body]]
|
|
383
|
+
|
|
384
|
+
#: Documentation of the return value, if written
|
|
385
|
+
returns: Final[Optional[docutils.nodes.field_body]]
|
|
386
|
+
|
|
387
|
+
# fmt: off
|
|
388
|
+
@require(
|
|
389
|
+
lambda arguments_by_name:
|
|
390
|
+
all(
|
|
391
|
+
find_first_field_list(body) is None
|
|
392
|
+
for body in arguments_by_name.values()
|
|
393
|
+
),
|
|
394
|
+
"Argument descriptions expected without field lists"
|
|
395
|
+
)
|
|
396
|
+
@require(
|
|
397
|
+
lambda returns:
|
|
398
|
+
not (returns is not None)
|
|
399
|
+
or find_first_field_list(returns) is None,
|
|
400
|
+
"Return value description expected without field lists"
|
|
401
|
+
)
|
|
402
|
+
# fmt: on
|
|
403
|
+
def __init__(
|
|
404
|
+
self,
|
|
405
|
+
summary: docutils.nodes.paragraph,
|
|
406
|
+
remarks: Sequence[docutils.nodes.Element],
|
|
407
|
+
arguments_by_name: OrderedDict[Identifier, docutils.nodes.field_body],
|
|
408
|
+
returns: Optional[docutils.nodes.field_body],
|
|
409
|
+
parsed: parse.Description,
|
|
410
|
+
) -> None:
|
|
411
|
+
"""Initialize with the given values."""
|
|
412
|
+
SummaryRemarksDescription.__init__(
|
|
413
|
+
self, summary=summary, remarks=remarks, parsed=parsed
|
|
414
|
+
)
|
|
415
|
+
self.arguments_by_name = arguments_by_name
|
|
416
|
+
self.returns = returns
|
|
417
|
+
|
|
418
|
+
def __repr__(self) -> str:
|
|
419
|
+
"""Represent the instance as a string for easier debugging."""
|
|
420
|
+
return f"<{_MODULE_NAME}.{self.__class__.__name__} at 0x{id(self):x}>"
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
class DescriptionOfConstant(SummaryRemarksDescription):
|
|
424
|
+
"""Represent a documentation of a constant in the meta-model."""
|
|
425
|
+
|
|
426
|
+
def __repr__(self) -> str:
|
|
427
|
+
"""Represent the instance as a string for easier debugging."""
|
|
428
|
+
return f"<{_MODULE_NAME}.{self.__class__.__name__} at 0x{id(self):x}>"
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
# endregion
|
|
432
|
+
|
|
433
|
+
# region Our types
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
class Property:
|
|
437
|
+
"""Represent a property of a class."""
|
|
438
|
+
|
|
439
|
+
#: Name of the property
|
|
440
|
+
name: Final[Identifier]
|
|
441
|
+
|
|
442
|
+
#: Type annotation of the property
|
|
443
|
+
type_annotation: Final[TypeAnnotationUnion]
|
|
444
|
+
|
|
445
|
+
#: Description of the property, if any
|
|
446
|
+
description: Final[Optional[DescriptionOfProperty]]
|
|
447
|
+
|
|
448
|
+
#: The original class where this property is specified.
|
|
449
|
+
#: We stack all the properties over the ancestors, so using ``specified_for``
|
|
450
|
+
#: you can distinguish between inherited properties and genuine properties of
|
|
451
|
+
#: a class.
|
|
452
|
+
specified_for: Final["Class"]
|
|
453
|
+
|
|
454
|
+
#: Relation to the property from the parse stage
|
|
455
|
+
parsed: Final[parse.Property]
|
|
456
|
+
|
|
457
|
+
def __init__(
|
|
458
|
+
self,
|
|
459
|
+
name: Identifier,
|
|
460
|
+
type_annotation: TypeAnnotationUnion,
|
|
461
|
+
description: Optional[DescriptionOfProperty],
|
|
462
|
+
specified_for: "Class",
|
|
463
|
+
parsed: parse.Property,
|
|
464
|
+
) -> None:
|
|
465
|
+
"""Initialize with the given values."""
|
|
466
|
+
self.name = name
|
|
467
|
+
self.type_annotation = type_annotation
|
|
468
|
+
self.description = description
|
|
469
|
+
self.specified_for = specified_for
|
|
470
|
+
self.parsed = parsed
|
|
471
|
+
|
|
472
|
+
def __repr__(self) -> str:
|
|
473
|
+
"""Represent the instance as a string for easier debugging."""
|
|
474
|
+
return (
|
|
475
|
+
f"<{_MODULE_NAME}.{self.__class__.__name__} {self.name} at 0x{id(self):x}>"
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
class DefaultPrimitive:
|
|
480
|
+
"""Represent a primitive value as a default for an argument."""
|
|
481
|
+
|
|
482
|
+
#: The default value
|
|
483
|
+
value: Final[Union[bool, int, float, str, None]]
|
|
484
|
+
|
|
485
|
+
#: Relation to the parsed stage
|
|
486
|
+
parsed: Final[parse.Default]
|
|
487
|
+
|
|
488
|
+
def __init__(
|
|
489
|
+
self, value: Union[bool, int, float, str, None], parsed: parse.Default
|
|
490
|
+
) -> None:
|
|
491
|
+
"""Initialize with the given values."""
|
|
492
|
+
self.value = value
|
|
493
|
+
self.parsed = parsed
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
class DefaultEnumerationLiteral:
|
|
497
|
+
"""Represent an enumeration literal as a default for an argument."""
|
|
498
|
+
|
|
499
|
+
#: Related enumeration
|
|
500
|
+
enumeration: Final["Enumeration"]
|
|
501
|
+
|
|
502
|
+
#: Related enumeration literal
|
|
503
|
+
literal: Final["EnumerationLiteral"]
|
|
504
|
+
|
|
505
|
+
#: Relation to the parse stage
|
|
506
|
+
parsed: Final[parse.Default]
|
|
507
|
+
|
|
508
|
+
# fmt: off
|
|
509
|
+
@require(
|
|
510
|
+
lambda enumeration, literal:
|
|
511
|
+
literal.name in enumeration.literals_by_name
|
|
512
|
+
and enumeration.literals_by_name[literal.name] == literal
|
|
513
|
+
)
|
|
514
|
+
# fmt: on
|
|
515
|
+
def __init__(
|
|
516
|
+
self,
|
|
517
|
+
enumeration: "Enumeration",
|
|
518
|
+
literal: "EnumerationLiteral",
|
|
519
|
+
parsed: parse.Default,
|
|
520
|
+
) -> None:
|
|
521
|
+
"""Initialize with the given values."""
|
|
522
|
+
self.parsed = parsed
|
|
523
|
+
self.enumeration = enumeration
|
|
524
|
+
self.literal = literal
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
Default = Union[DefaultPrimitive, DefaultEnumerationLiteral]
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
class Argument:
|
|
531
|
+
"""Represent an argument of a method (both of an interface and of class)."""
|
|
532
|
+
|
|
533
|
+
#: Name of the argument
|
|
534
|
+
name: Final[Identifier]
|
|
535
|
+
|
|
536
|
+
#: Type annotation of the argument
|
|
537
|
+
type_annotation: Final[TypeAnnotationUnion]
|
|
538
|
+
|
|
539
|
+
#: Default value of the argument, if any
|
|
540
|
+
default: Final[Optional[Default]]
|
|
541
|
+
|
|
542
|
+
#: Relation to the parse stage
|
|
543
|
+
parsed: Final[parse.Argument]
|
|
544
|
+
|
|
545
|
+
def __init__(
|
|
546
|
+
self,
|
|
547
|
+
name: Identifier,
|
|
548
|
+
type_annotation: TypeAnnotationUnion,
|
|
549
|
+
default: Optional[Default],
|
|
550
|
+
parsed: parse.Argument,
|
|
551
|
+
) -> None:
|
|
552
|
+
"""Initialize with the given values."""
|
|
553
|
+
self.name = name
|
|
554
|
+
self.type_annotation = type_annotation
|
|
555
|
+
self.default = default
|
|
556
|
+
self.parsed = parsed
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
class Serialization:
|
|
560
|
+
"""Specify the general settings for serialization of an interface or a class."""
|
|
561
|
+
|
|
562
|
+
def __init__(self, with_model_type: bool) -> None:
|
|
563
|
+
"""
|
|
564
|
+
Initialize with the given values.
|
|
565
|
+
|
|
566
|
+
:param with_model_type:
|
|
567
|
+
if set, the serialization needs to include a discriminator.
|
|
568
|
+
"""
|
|
569
|
+
self.with_model_type = with_model_type
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
class Invariant:
|
|
573
|
+
"""Represent an invariant of a class."""
|
|
574
|
+
|
|
575
|
+
#: Human-readable description of the invariant
|
|
576
|
+
description: Final[str]
|
|
577
|
+
|
|
578
|
+
#: Understood body of the invariant
|
|
579
|
+
body: Final[parse_tree.Expression]
|
|
580
|
+
|
|
581
|
+
#: The original our type where this invariant is specified.
|
|
582
|
+
#: We stack all the invariants over the ancestors, so using ``specified_for``
|
|
583
|
+
#: you can distinguish between inherited invariants and genuine invariants of
|
|
584
|
+
#: a class or a constrained primitive.
|
|
585
|
+
specified_for: Final[Union["ConstrainedPrimitive", "Class"]]
|
|
586
|
+
|
|
587
|
+
#: Relation to the parse stage
|
|
588
|
+
parsed: Final[parse.Invariant]
|
|
589
|
+
|
|
590
|
+
def __init__(
|
|
591
|
+
self,
|
|
592
|
+
description: str,
|
|
593
|
+
body: parse_tree.Expression,
|
|
594
|
+
specified_for: Union["ConstrainedPrimitive", "Class"],
|
|
595
|
+
parsed: parse.Invariant,
|
|
596
|
+
) -> None:
|
|
597
|
+
self.description = description
|
|
598
|
+
self.body = body
|
|
599
|
+
self.specified_for = specified_for
|
|
600
|
+
self.parsed = parsed
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
class Contract:
|
|
604
|
+
"""Represent a contract of a method."""
|
|
605
|
+
|
|
606
|
+
#: Argument names of the contract
|
|
607
|
+
args: Final[Sequence[Identifier]]
|
|
608
|
+
|
|
609
|
+
#: Human-readable description of the contract, if any
|
|
610
|
+
description: Final[Optional[str]]
|
|
611
|
+
|
|
612
|
+
#: Understood body of the contract
|
|
613
|
+
body: Final[parse_tree.Node]
|
|
614
|
+
|
|
615
|
+
#: Relation to the parse stage
|
|
616
|
+
parsed: Final[parse.Contract]
|
|
617
|
+
|
|
618
|
+
def __init__(
|
|
619
|
+
self,
|
|
620
|
+
args: Sequence[Identifier],
|
|
621
|
+
description: Optional[str],
|
|
622
|
+
body: parse_tree.Node,
|
|
623
|
+
parsed: parse.Contract,
|
|
624
|
+
) -> None:
|
|
625
|
+
"""Initialize with the given values."""
|
|
626
|
+
self.args = args
|
|
627
|
+
self.description = description
|
|
628
|
+
self.body = body
|
|
629
|
+
self.parsed = parsed
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
class Snapshot:
|
|
633
|
+
"""Represent a snapshot of an OLD value capture before the method execution."""
|
|
634
|
+
|
|
635
|
+
#: Argument names of the snapshot
|
|
636
|
+
args: Final[Sequence[Identifier]]
|
|
637
|
+
|
|
638
|
+
#: Understood body of the snapshot
|
|
639
|
+
body: Final[parse_tree.Node]
|
|
640
|
+
|
|
641
|
+
#: Name of the snapshot variable
|
|
642
|
+
name: Final[Identifier]
|
|
643
|
+
|
|
644
|
+
#: Relation to parse stage
|
|
645
|
+
parsed: Final[parse.Snapshot]
|
|
646
|
+
|
|
647
|
+
def __init__(
|
|
648
|
+
self,
|
|
649
|
+
args: Sequence[Identifier],
|
|
650
|
+
body: parse_tree.Node,
|
|
651
|
+
name: Identifier,
|
|
652
|
+
parsed: parse.Snapshot,
|
|
653
|
+
) -> None:
|
|
654
|
+
"""Initialize with the given values."""
|
|
655
|
+
self.args = args
|
|
656
|
+
self.body = body
|
|
657
|
+
self.name = name
|
|
658
|
+
self.parsed = parsed
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
class Contracts:
|
|
662
|
+
"""Represent the set of contracts for a method or a function."""
|
|
663
|
+
|
|
664
|
+
# NOTE (mristin, 2022-04-07):
|
|
665
|
+
# Common programming languages which work with contracts usually implement
|
|
666
|
+
# pre-conditions in a disjunctive normal form, *i.e.* as a disjunction of
|
|
667
|
+
# conjunctions, where at least one conjunction needs to hold. The individual
|
|
668
|
+
# conjunctions correspond to the levels of the inheritance hierarchy.
|
|
669
|
+
#
|
|
670
|
+
# However, we have not touched methods at the moment nor their proper inheritance.
|
|
671
|
+
# Therefore, we leave the pre-conditions in the intermediate representation as they
|
|
672
|
+
# would appear in the code, without inheritance and hence without disjunctions.
|
|
673
|
+
# In the future, once we want to tackle the methods as a feature, we need to change
|
|
674
|
+
# the way how we model and resolve the pre-conditions through
|
|
675
|
+
# the inheritance hierarchy.
|
|
676
|
+
|
|
677
|
+
#: Pre-conditions that need to hold *before* the call
|
|
678
|
+
preconditions: Final[Sequence[Contract]]
|
|
679
|
+
|
|
680
|
+
#: Snapshots which are captured *before* the call
|
|
681
|
+
snapshots: Final[Sequence[Snapshot]]
|
|
682
|
+
|
|
683
|
+
#: Post-conditions that need to hold *after* the call
|
|
684
|
+
postconditions: Final[Sequence[Contract]]
|
|
685
|
+
|
|
686
|
+
def __init__(
|
|
687
|
+
self,
|
|
688
|
+
preconditions: Sequence[Contract],
|
|
689
|
+
snapshots: Sequence[Snapshot],
|
|
690
|
+
postconditions: Sequence[Contract],
|
|
691
|
+
) -> None:
|
|
692
|
+
"""Initialize with the given values."""
|
|
693
|
+
self.preconditions = preconditions
|
|
694
|
+
self.snapshots = snapshots
|
|
695
|
+
self.postconditions = postconditions
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
class SignatureLike(DBC):
|
|
699
|
+
"""
|
|
700
|
+
Represent a signature-like "something".
|
|
701
|
+
|
|
702
|
+
This can be either a signature of a method, a method or a function.
|
|
703
|
+
"""
|
|
704
|
+
|
|
705
|
+
#: Name of the signature-like
|
|
706
|
+
name: Final[Identifier]
|
|
707
|
+
|
|
708
|
+
#: Arguments of the signature-like
|
|
709
|
+
arguments: Final[Sequence[Argument]]
|
|
710
|
+
|
|
711
|
+
#: Return type of the signature-like
|
|
712
|
+
returns: Final[Optional[TypeAnnotationUnion]]
|
|
713
|
+
|
|
714
|
+
#: Description of the signature-like, if any
|
|
715
|
+
description: Final[Optional[DescriptionOfSignature]]
|
|
716
|
+
|
|
717
|
+
#: List of contracts of the signature-like. The contracts are stacked from the
|
|
718
|
+
#: ancestors.
|
|
719
|
+
contracts: Final[Contracts]
|
|
720
|
+
|
|
721
|
+
# NOTE (mristin, 2021-12-26):
|
|
722
|
+
# The ``parsed`` must be optional since constructors can be synthesized without
|
|
723
|
+
# being defined in the original meta-model.
|
|
724
|
+
|
|
725
|
+
#: Relation to the parse stage
|
|
726
|
+
parsed: Optional[parse.Method]
|
|
727
|
+
|
|
728
|
+
#: Map arguments by their names
|
|
729
|
+
arguments_by_name: Final[Mapping[Identifier, Argument]]
|
|
730
|
+
|
|
731
|
+
# fmt: off
|
|
732
|
+
@require(
|
|
733
|
+
lambda arguments:
|
|
734
|
+
all(
|
|
735
|
+
arg.name != 'self'
|
|
736
|
+
for arg in arguments
|
|
737
|
+
),
|
|
738
|
+
"No explicit ``self`` argument in the arguments"
|
|
739
|
+
)
|
|
740
|
+
@require(
|
|
741
|
+
lambda arguments: (
|
|
742
|
+
arg_names := [arg.name for arg in arguments],
|
|
743
|
+
len(arg_names) == len(set(arg_names))
|
|
744
|
+
)[1],
|
|
745
|
+
"Unique arguments"
|
|
746
|
+
)
|
|
747
|
+
@ensure(
|
|
748
|
+
lambda self:
|
|
749
|
+
len(self.arguments) == len(self.arguments_by_name)
|
|
750
|
+
and all(
|
|
751
|
+
(
|
|
752
|
+
found_argument := self.arguments_by_name.get(argument.name, None),
|
|
753
|
+
found_argument is not None and found_argument is argument
|
|
754
|
+
)[1]
|
|
755
|
+
for argument in self.arguments
|
|
756
|
+
),
|
|
757
|
+
"Arguments and arguments-by-name consistent"
|
|
758
|
+
)
|
|
759
|
+
# fmt: on
|
|
760
|
+
def __init__(
|
|
761
|
+
self,
|
|
762
|
+
name: Identifier,
|
|
763
|
+
arguments: Sequence[Argument],
|
|
764
|
+
returns: Optional[TypeAnnotationUnion],
|
|
765
|
+
description: Optional[DescriptionOfSignature],
|
|
766
|
+
contracts: Contracts,
|
|
767
|
+
parsed: Optional[parse.Method],
|
|
768
|
+
) -> None:
|
|
769
|
+
"""Initialize with the given values."""
|
|
770
|
+
self.name = name
|
|
771
|
+
self.arguments = arguments
|
|
772
|
+
self.returns = returns
|
|
773
|
+
self.description = description
|
|
774
|
+
self.contracts = contracts
|
|
775
|
+
self.parsed = parsed
|
|
776
|
+
|
|
777
|
+
self.arguments_by_name = {
|
|
778
|
+
argument.name: argument for argument in self.arguments
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
@abc.abstractmethod
|
|
782
|
+
def __repr__(self) -> str:
|
|
783
|
+
# Signal that this is a pure abstract class
|
|
784
|
+
raise NotImplementedError()
|
|
785
|
+
|
|
786
|
+
|
|
787
|
+
class Method(SignatureLike):
|
|
788
|
+
"""Represent a method of a class."""
|
|
789
|
+
|
|
790
|
+
# NOTE (mristin, 2021-12-26):
|
|
791
|
+
# The ``parsed`` must be optional in the parent class, ``SignatureLike``, since
|
|
792
|
+
# constructors can be synthesized without being defined in the original meta-model.
|
|
793
|
+
#
|
|
794
|
+
# However, methods are never synthesized, so we always have a clear link to
|
|
795
|
+
# the parse stage.
|
|
796
|
+
|
|
797
|
+
parsed: parse.Method
|
|
798
|
+
|
|
799
|
+
#: The original class where this method is specified.
|
|
800
|
+
#: We stack all the methods over the ancestors, so using ``specified_for``
|
|
801
|
+
#: you can distinguish between inherited methods and genuine methods of
|
|
802
|
+
#: a class.
|
|
803
|
+
specified_for: Final["Class"]
|
|
804
|
+
|
|
805
|
+
#: If set, the method does not mutate the instance data.
|
|
806
|
+
#:
|
|
807
|
+
#: We do not check for non-mutating methods in any way as this is very complex,
|
|
808
|
+
#: so we leave it out-of-scope for the moment (2023-07-06).
|
|
809
|
+
non_mutating: Final[bool]
|
|
810
|
+
|
|
811
|
+
# fmt: off
|
|
812
|
+
@require(
|
|
813
|
+
lambda name:
|
|
814
|
+
name != "__init__",
|
|
815
|
+
"Expected constructors to be handled in a special way and not as a method"
|
|
816
|
+
)
|
|
817
|
+
@require(
|
|
818
|
+
lambda arguments, contracts:
|
|
819
|
+
(
|
|
820
|
+
arg_set := {arg.name for arg in arguments},
|
|
821
|
+
all(
|
|
822
|
+
arg in arg_set # pylint: disable=used-before-assignment
|
|
823
|
+
for precondition in contracts.preconditions
|
|
824
|
+
for arg in precondition.args
|
|
825
|
+
if arg != 'self'
|
|
826
|
+
)
|
|
827
|
+
and all(
|
|
828
|
+
arg in arg_set
|
|
829
|
+
for postcondition in contracts.postconditions
|
|
830
|
+
for arg in postcondition.args
|
|
831
|
+
if arg not in ('OLD', 'result', 'self')
|
|
832
|
+
)
|
|
833
|
+
and all(
|
|
834
|
+
arg in arg_set
|
|
835
|
+
for snapshot in contracts.snapshots
|
|
836
|
+
for arg in snapshot.args
|
|
837
|
+
if arg.name != 'self'
|
|
838
|
+
)
|
|
839
|
+
)[1],
|
|
840
|
+
"All arguments of contracts defined in method arguments except ``self``"
|
|
841
|
+
)
|
|
842
|
+
# fmt: on
|
|
843
|
+
def __init__(
|
|
844
|
+
self,
|
|
845
|
+
name: Identifier,
|
|
846
|
+
arguments: Sequence[Argument],
|
|
847
|
+
returns: Optional[TypeAnnotationUnion],
|
|
848
|
+
description: Optional[DescriptionOfSignature],
|
|
849
|
+
specified_for: "Class",
|
|
850
|
+
contracts: Contracts,
|
|
851
|
+
non_mutating: bool,
|
|
852
|
+
parsed: parse.Method,
|
|
853
|
+
) -> None:
|
|
854
|
+
"""Initialize with the given values."""
|
|
855
|
+
SignatureLike.__init__(
|
|
856
|
+
self,
|
|
857
|
+
name=name,
|
|
858
|
+
arguments=arguments,
|
|
859
|
+
returns=returns,
|
|
860
|
+
description=description,
|
|
861
|
+
contracts=contracts,
|
|
862
|
+
parsed=parsed,
|
|
863
|
+
)
|
|
864
|
+
|
|
865
|
+
self.non_mutating = non_mutating
|
|
866
|
+
self.specified_for = specified_for
|
|
867
|
+
|
|
868
|
+
@abc.abstractmethod
|
|
869
|
+
def __repr__(self) -> str:
|
|
870
|
+
# Signal that this is a pure abstract class.
|
|
871
|
+
raise NotImplementedError()
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
# NOTE (mristin, 2021-12-19):
|
|
875
|
+
# At the moment, we support only implementation-specific methods. However, we anticipate
|
|
876
|
+
# that we will try to understand the methods in the very near future, so we already
|
|
877
|
+
# prepare the class hierarchy for it.
|
|
878
|
+
|
|
879
|
+
|
|
880
|
+
class ImplementationSpecificMethod(Method):
|
|
881
|
+
"""Represent an implementation-specific method of a class."""
|
|
882
|
+
|
|
883
|
+
# NOTE (mristin, 2021-12-26):
|
|
884
|
+
# The ``parsed`` must be optional in the parent class, ``SignatureLike``, since
|
|
885
|
+
# constructors can be synthesized without being defined in the original meta-model.
|
|
886
|
+
#
|
|
887
|
+
# However, methods are never synthesized, so we always have a clear link to
|
|
888
|
+
# the parse stage here.
|
|
889
|
+
|
|
890
|
+
#: Relation to parse stage
|
|
891
|
+
parsed: parse.Method
|
|
892
|
+
|
|
893
|
+
def __repr__(self) -> str:
|
|
894
|
+
"""Represent the instance as a string for easier debugging."""
|
|
895
|
+
return (
|
|
896
|
+
f"<{_MODULE_NAME}.{self.__class__.__name__} {self.name} at 0x{id(self):x}>"
|
|
897
|
+
)
|
|
898
|
+
|
|
899
|
+
|
|
900
|
+
class UnderstoodMethod(Method):
|
|
901
|
+
"""Represent a method of a class which we could understand."""
|
|
902
|
+
|
|
903
|
+
#: Understood syntax tree of the method's body
|
|
904
|
+
body: Final[Sequence[parse_tree.Node]]
|
|
905
|
+
|
|
906
|
+
# NOTE (mristin, 2021-12-26):
|
|
907
|
+
# The ``parsed`` must be optional in the parent class, ``SignatureLike``, since
|
|
908
|
+
# constructors can be synthesized without being defined in the original meta-model.
|
|
909
|
+
#
|
|
910
|
+
# However, methods are never synthesized, so we always have a clear link to
|
|
911
|
+
# the parse stage here.
|
|
912
|
+
|
|
913
|
+
#: Relation to parse stage
|
|
914
|
+
parsed: parse.Method
|
|
915
|
+
|
|
916
|
+
def __init__(
|
|
917
|
+
self,
|
|
918
|
+
name: Identifier,
|
|
919
|
+
arguments: Sequence[Argument],
|
|
920
|
+
returns: Optional[TypeAnnotationUnion],
|
|
921
|
+
description: Optional[DescriptionOfSignature],
|
|
922
|
+
specified_for: "Class",
|
|
923
|
+
contracts: Contracts,
|
|
924
|
+
non_mutating: bool,
|
|
925
|
+
body: Sequence[parse_tree.Node],
|
|
926
|
+
parsed: parse.Method,
|
|
927
|
+
) -> None:
|
|
928
|
+
"""Initialize with the given values."""
|
|
929
|
+
Method.__init__(
|
|
930
|
+
self,
|
|
931
|
+
name=name,
|
|
932
|
+
arguments=arguments,
|
|
933
|
+
returns=returns,
|
|
934
|
+
description=description,
|
|
935
|
+
specified_for=specified_for,
|
|
936
|
+
contracts=contracts,
|
|
937
|
+
non_mutating=non_mutating,
|
|
938
|
+
parsed=parsed,
|
|
939
|
+
)
|
|
940
|
+
|
|
941
|
+
self.body = body
|
|
942
|
+
|
|
943
|
+
def __repr__(self) -> str:
|
|
944
|
+
"""Represent the instance as a string for easier debugging."""
|
|
945
|
+
return (
|
|
946
|
+
f"<{_MODULE_NAME}.{self.__class__.__name__} {self.name} at 0x{id(self):x}>"
|
|
947
|
+
)
|
|
948
|
+
|
|
949
|
+
|
|
950
|
+
class Constructor(SignatureLike):
|
|
951
|
+
"""
|
|
952
|
+
Represent an understood constructor of a class stacked.
|
|
953
|
+
|
|
954
|
+
The constructor is expected to be stacked from the class and all the ancestors.
|
|
955
|
+
"""
|
|
956
|
+
|
|
957
|
+
#: Interpreted statements of the constructor, including calls to super constructors
|
|
958
|
+
statements: Final[Sequence[construction.Statement]]
|
|
959
|
+
|
|
960
|
+
#: Interpreted statements of the constructor stacked over all the ancestors
|
|
961
|
+
#:
|
|
962
|
+
#: ``inlined_statements`` are semantically equivalent to ``statements``. Usually
|
|
963
|
+
#: you want to use them instead of ``statements`` when you deal with languages
|
|
964
|
+
#: which do not support multiple inheritance, so that calls to multiple super
|
|
965
|
+
#: constructors are not possible.
|
|
966
|
+
inlined_statements: Final[Sequence[construction.AssignArgument]]
|
|
967
|
+
|
|
968
|
+
#: If set, the constructor is implementation-specific, and we need to provide
|
|
969
|
+
#: a snippet for it.
|
|
970
|
+
is_implementation_specific: Final[bool]
|
|
971
|
+
|
|
972
|
+
def __init__(
|
|
973
|
+
self,
|
|
974
|
+
is_implementation_specific: bool,
|
|
975
|
+
arguments: Sequence[Argument],
|
|
976
|
+
contracts: Contracts,
|
|
977
|
+
description: Optional[DescriptionOfSignature],
|
|
978
|
+
statements: Sequence[construction.Statement],
|
|
979
|
+
inlined_statements: Sequence[construction.AssignArgument],
|
|
980
|
+
parsed: Optional[parse.Method],
|
|
981
|
+
) -> None:
|
|
982
|
+
SignatureLike.__init__(
|
|
983
|
+
self,
|
|
984
|
+
name=Identifier("__init__"),
|
|
985
|
+
arguments=arguments,
|
|
986
|
+
returns=None,
|
|
987
|
+
description=description,
|
|
988
|
+
contracts=contracts,
|
|
989
|
+
parsed=parsed,
|
|
990
|
+
)
|
|
991
|
+
|
|
992
|
+
self.is_implementation_specific = is_implementation_specific
|
|
993
|
+
|
|
994
|
+
self.statements = statements
|
|
995
|
+
self.inlined_statements = inlined_statements
|
|
996
|
+
|
|
997
|
+
def __repr__(self) -> str:
|
|
998
|
+
"""Represent the instance as a string for easier debugging."""
|
|
999
|
+
return f"<{_MODULE_NAME}.{self.__class__.__name__} at 0x{id(self):x}>"
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
class EnumerationLiteral:
|
|
1003
|
+
"""Represent a single enumeration literal."""
|
|
1004
|
+
|
|
1005
|
+
def __init__(
|
|
1006
|
+
self,
|
|
1007
|
+
name: Identifier,
|
|
1008
|
+
value: str,
|
|
1009
|
+
description: Optional[DescriptionOfEnumerationLiteral],
|
|
1010
|
+
parsed: parse.EnumerationLiteral,
|
|
1011
|
+
) -> None:
|
|
1012
|
+
self.name = name
|
|
1013
|
+
self.value = value
|
|
1014
|
+
self.description = description
|
|
1015
|
+
self.parsed = parsed
|
|
1016
|
+
|
|
1017
|
+
|
|
1018
|
+
# fmt: off
|
|
1019
|
+
@invariant(
|
|
1020
|
+
lambda self:
|
|
1021
|
+
all(
|
|
1022
|
+
literal == self.literals_by_value[literal.value]
|
|
1023
|
+
for literal in self.literals
|
|
1024
|
+
),
|
|
1025
|
+
"Literal map by value consistent on value"
|
|
1026
|
+
)
|
|
1027
|
+
@invariant(
|
|
1028
|
+
lambda self:
|
|
1029
|
+
sorted(map(id, self.literals_by_value.values())) == sorted(map(id, self.literals)),
|
|
1030
|
+
"Literal map by value complete"
|
|
1031
|
+
)
|
|
1032
|
+
@invariant(
|
|
1033
|
+
lambda self:
|
|
1034
|
+
all(
|
|
1035
|
+
literal == self.literals_by_name[literal.name]
|
|
1036
|
+
for literal in self.literals
|
|
1037
|
+
),
|
|
1038
|
+
"Literal map by name consistent on name"
|
|
1039
|
+
)
|
|
1040
|
+
@invariant(
|
|
1041
|
+
lambda self:
|
|
1042
|
+
sorted(map(id, self.literals_by_name.values())) == sorted(map(id, self.literals)),
|
|
1043
|
+
"Literal map by name complete"
|
|
1044
|
+
)
|
|
1045
|
+
# fmt: on
|
|
1046
|
+
class Enumeration:
|
|
1047
|
+
"""Represent an enumeration."""
|
|
1048
|
+
|
|
1049
|
+
#: Name of the enumeration
|
|
1050
|
+
name: Final[Identifier]
|
|
1051
|
+
|
|
1052
|
+
#: Literals associated with the enumeration
|
|
1053
|
+
literals: Final[Sequence[EnumerationLiteral]]
|
|
1054
|
+
|
|
1055
|
+
#: Description of the enumeration, if any
|
|
1056
|
+
description: Final[Optional[DescriptionOfOurType]]
|
|
1057
|
+
|
|
1058
|
+
#: Map literals by their identifiers
|
|
1059
|
+
literals_by_name: Final[Mapping[str, EnumerationLiteral]]
|
|
1060
|
+
|
|
1061
|
+
# NOTE (mristin, 2022-09-01):
|
|
1062
|
+
# This map is used by the downstream code, *e.g.*, aas-core3.0rc02-testgen.
|
|
1063
|
+
#: Map literals by their values
|
|
1064
|
+
literals_by_value: Final[Mapping[str, EnumerationLiteral]]
|
|
1065
|
+
|
|
1066
|
+
#: Collect IDs (with :py:func:`id`) of the literal objects in a set
|
|
1067
|
+
literal_id_set: Final[FrozenSet[int]]
|
|
1068
|
+
|
|
1069
|
+
def __init__(
|
|
1070
|
+
self,
|
|
1071
|
+
name: Identifier,
|
|
1072
|
+
literals: Sequence[EnumerationLiteral],
|
|
1073
|
+
description: Optional[DescriptionOfOurType],
|
|
1074
|
+
parsed: parse.Enumeration,
|
|
1075
|
+
) -> None:
|
|
1076
|
+
self.name = name
|
|
1077
|
+
self.literals = literals
|
|
1078
|
+
self.description = description
|
|
1079
|
+
self.parsed = parsed
|
|
1080
|
+
|
|
1081
|
+
self.literals_by_name: Mapping[str, EnumerationLiteral] = {
|
|
1082
|
+
literal.name: literal for literal in self.literals
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
self.literals_by_value: Mapping[str, EnumerationLiteral] = {
|
|
1086
|
+
literal.value: literal for literal in self.literals
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
self.literal_id_set = frozenset(id(literal) for literal in literals)
|
|
1090
|
+
|
|
1091
|
+
def __repr__(self) -> str:
|
|
1092
|
+
"""Represent the instance as a string for easier debugging."""
|
|
1093
|
+
return (
|
|
1094
|
+
f"<{_MODULE_NAME}.{self.__class__.__name__} {self.name} at 0x{id(self):x}>"
|
|
1095
|
+
)
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
class ConstrainedPrimitive:
|
|
1099
|
+
"""Represent a primitive type constrained by one or more invariants."""
|
|
1100
|
+
|
|
1101
|
+
#: Name of the class
|
|
1102
|
+
name: Final[Identifier]
|
|
1103
|
+
|
|
1104
|
+
# region Inheritances
|
|
1105
|
+
|
|
1106
|
+
# NOTE (mristin, 2021-12-24):
|
|
1107
|
+
# We have to decorate inheritances with ``@property`` so that the client code is
|
|
1108
|
+
# forced to use ``_set_inheritances``.
|
|
1109
|
+
|
|
1110
|
+
_inheritances: Sequence["ConstrainedPrimitive"]
|
|
1111
|
+
|
|
1112
|
+
_inheritance_id_set: FrozenSet[int]
|
|
1113
|
+
|
|
1114
|
+
# endregion
|
|
1115
|
+
|
|
1116
|
+
# region Ancestors
|
|
1117
|
+
|
|
1118
|
+
# NOTE (mristin, 2023-03-17):
|
|
1119
|
+
# We have to decorate ancestors with ``@property`` so that the translation code
|
|
1120
|
+
# is forced to use ``_set_ancestors``.
|
|
1121
|
+
|
|
1122
|
+
_ancestors: Sequence["ConstrainedPrimitive"]
|
|
1123
|
+
|
|
1124
|
+
_ancestor_id_set: FrozenSet[int]
|
|
1125
|
+
|
|
1126
|
+
# endregion
|
|
1127
|
+
|
|
1128
|
+
# region Descendants
|
|
1129
|
+
|
|
1130
|
+
# NOTE (mristin, 2021-12-24):
|
|
1131
|
+
# We have to decorate ``descendant_id_set`` with
|
|
1132
|
+
# ``@property`` so that the translation code is forced to use
|
|
1133
|
+
# ``_set_descendants``.
|
|
1134
|
+
|
|
1135
|
+
_descendant_id_set: FrozenSet[int]
|
|
1136
|
+
|
|
1137
|
+
# endregion
|
|
1138
|
+
|
|
1139
|
+
#: Which primitive type is constrained
|
|
1140
|
+
constrainee: PrimitiveType
|
|
1141
|
+
|
|
1142
|
+
#: If set, this class is implementation-specific, and we need to provide a snippet
|
|
1143
|
+
#: for each implementation target
|
|
1144
|
+
is_implementation_specific: Final[bool]
|
|
1145
|
+
|
|
1146
|
+
# region Invariants
|
|
1147
|
+
|
|
1148
|
+
# NOTE (mristin, 2022-03-19):
|
|
1149
|
+
# We have to decorate invariants with ``@property`` so that the translation code
|
|
1150
|
+
# is forced to use ``_set_invariants``.
|
|
1151
|
+
|
|
1152
|
+
_invariants: Sequence[Invariant]
|
|
1153
|
+
|
|
1154
|
+
_invariant_id_set: FrozenSet[int]
|
|
1155
|
+
|
|
1156
|
+
# endregion
|
|
1157
|
+
|
|
1158
|
+
#: Description of the class
|
|
1159
|
+
description: Final[Optional[DescriptionOfOurType]]
|
|
1160
|
+
|
|
1161
|
+
#: Relation to the class from the parse stage
|
|
1162
|
+
parsed: parse.Class
|
|
1163
|
+
|
|
1164
|
+
@require(lambda self, ancestors: self not in ancestors)
|
|
1165
|
+
def _set_ancestors(self, ancestors: Sequence["ConstrainedPrimitive"]) -> None:
|
|
1166
|
+
"""
|
|
1167
|
+
Set the ancestors in the constrained primitive.
|
|
1168
|
+
|
|
1169
|
+
This method is expected to be called only during the translation phase.
|
|
1170
|
+
"""
|
|
1171
|
+
self._ancestors = ancestors
|
|
1172
|
+
|
|
1173
|
+
self._ancestor_id_set = frozenset(id(ancestor) for ancestor in ancestors)
|
|
1174
|
+
|
|
1175
|
+
@require(lambda self, descendants: self not in descendants)
|
|
1176
|
+
def _set_descendants(self, descendants: Sequence["ConstrainedPrimitive"]) -> None:
|
|
1177
|
+
"""
|
|
1178
|
+
Set the descendants in the constrained primitive.
|
|
1179
|
+
|
|
1180
|
+
This method is expected to be called only during the translation phase.
|
|
1181
|
+
"""
|
|
1182
|
+
self._descendant_id_set = frozenset(
|
|
1183
|
+
id(descendant) for descendant in descendants
|
|
1184
|
+
)
|
|
1185
|
+
|
|
1186
|
+
def _set_invariants(self, invariants: Sequence[Invariant]) -> None:
|
|
1187
|
+
"""
|
|
1188
|
+
Set the invariants in the class.
|
|
1189
|
+
|
|
1190
|
+
This method is expected to be called only during the translation phase.
|
|
1191
|
+
"""
|
|
1192
|
+
self._invariants = invariants
|
|
1193
|
+
self._invariant_id_set = frozenset(id(inv) for inv in invariants)
|
|
1194
|
+
|
|
1195
|
+
# fmt: off
|
|
1196
|
+
@require(
|
|
1197
|
+
lambda inheritances:
|
|
1198
|
+
len(inheritances) == len(set(inheritance.name for inheritance in inheritances)),
|
|
1199
|
+
"No duplicate inheritances"
|
|
1200
|
+
)
|
|
1201
|
+
# fmt: on
|
|
1202
|
+
def _set_inheritances(self, inheritances: Sequence["ConstrainedPrimitive"]) -> None:
|
|
1203
|
+
"""
|
|
1204
|
+
Set the inheritances in the class.
|
|
1205
|
+
|
|
1206
|
+
This method is expected to be called only during the translation phase.
|
|
1207
|
+
"""
|
|
1208
|
+
self._inheritances = inheritances
|
|
1209
|
+
|
|
1210
|
+
self._inheritance_id_set = frozenset(
|
|
1211
|
+
id(inheritance) for inheritance in self._inheritances
|
|
1212
|
+
)
|
|
1213
|
+
|
|
1214
|
+
# fmt: off
|
|
1215
|
+
@require(
|
|
1216
|
+
lambda parsed: len(parsed.methods) == 0,
|
|
1217
|
+
"No methods expected in the constrained primitive type"
|
|
1218
|
+
)
|
|
1219
|
+
@require(
|
|
1220
|
+
lambda parsed: len(parsed.properties) == 0,
|
|
1221
|
+
"No properties expected in the constrained primitive type"
|
|
1222
|
+
)
|
|
1223
|
+
@require(
|
|
1224
|
+
lambda constrainee, inheritances:
|
|
1225
|
+
all(
|
|
1226
|
+
inheritance.constrainee == constrainee
|
|
1227
|
+
for inheritance in inheritances
|
|
1228
|
+
),
|
|
1229
|
+
"Constrainee consistent with ancestors"
|
|
1230
|
+
)
|
|
1231
|
+
@require(
|
|
1232
|
+
lambda constrainee, descendants:
|
|
1233
|
+
all(
|
|
1234
|
+
descendant.constrainee == constrainee
|
|
1235
|
+
for descendant in descendants
|
|
1236
|
+
),
|
|
1237
|
+
"Constrainee consistent with descendants"
|
|
1238
|
+
)
|
|
1239
|
+
@require(
|
|
1240
|
+
lambda ancestors, inheritances:
|
|
1241
|
+
(
|
|
1242
|
+
ancestor_id_set := set(id(ancestor) for ancestor in ancestors),
|
|
1243
|
+
all(
|
|
1244
|
+
id(inheritance) in ancestor_id_set # pylint: disable=used-before-assignment
|
|
1245
|
+
for inheritance in inheritances
|
|
1246
|
+
)
|
|
1247
|
+
)[1],
|
|
1248
|
+
"Inheritances is a subset of ancestors"
|
|
1249
|
+
)
|
|
1250
|
+
@require(lambda self, inheritances: self not in inheritances)
|
|
1251
|
+
@require(lambda self, ancestors: self not in ancestors)
|
|
1252
|
+
@require(lambda self, descendants: self not in descendants)
|
|
1253
|
+
# fmt: on
|
|
1254
|
+
def __init__(
|
|
1255
|
+
self,
|
|
1256
|
+
name: Identifier,
|
|
1257
|
+
inheritances: Sequence["ConstrainedPrimitive"],
|
|
1258
|
+
ancestors: Sequence["ConstrainedPrimitive"],
|
|
1259
|
+
descendants: Sequence["ConstrainedPrimitive"],
|
|
1260
|
+
constrainee: PrimitiveType,
|
|
1261
|
+
is_implementation_specific: bool,
|
|
1262
|
+
invariants: Sequence[Invariant],
|
|
1263
|
+
description: Optional[DescriptionOfOurType],
|
|
1264
|
+
parsed: parse.Class,
|
|
1265
|
+
) -> None:
|
|
1266
|
+
self.name = name
|
|
1267
|
+
self._set_inheritances(inheritances)
|
|
1268
|
+
self._set_ancestors(ancestors)
|
|
1269
|
+
self._set_descendants(descendants)
|
|
1270
|
+
self.constrainee = constrainee
|
|
1271
|
+
self.is_implementation_specific = is_implementation_specific
|
|
1272
|
+
self._set_invariants(invariants)
|
|
1273
|
+
self.description = description
|
|
1274
|
+
self.parsed = parsed
|
|
1275
|
+
|
|
1276
|
+
@property
|
|
1277
|
+
def inheritances(self) -> Sequence["ConstrainedPrimitive"]:
|
|
1278
|
+
"""Return direct parents that this class inherits from."""
|
|
1279
|
+
return self._inheritances
|
|
1280
|
+
|
|
1281
|
+
@property
|
|
1282
|
+
def inheritance_id_set(self) -> FrozenSet[int]:
|
|
1283
|
+
"""Collect IDs (with :py:func:`id`) of the inheritance objects in a set."""
|
|
1284
|
+
return self._inheritance_id_set
|
|
1285
|
+
|
|
1286
|
+
@property
|
|
1287
|
+
def ancestors(self) -> Sequence["ConstrainedPrimitive"]:
|
|
1288
|
+
"""
|
|
1289
|
+
Return the ancestor constrained primitives.
|
|
1290
|
+
|
|
1291
|
+
These are the constrained primitives that this one directly or indirectly
|
|
1292
|
+
inherits from.
|
|
1293
|
+
"""
|
|
1294
|
+
return self._ancestors
|
|
1295
|
+
|
|
1296
|
+
@property
|
|
1297
|
+
def ancestor_id_set(self) -> FrozenSet[int]:
|
|
1298
|
+
"""Collect IDs (with :py:func:`id`) of the ancestors in a set."""
|
|
1299
|
+
return self._ancestor_id_set
|
|
1300
|
+
|
|
1301
|
+
def is_subclass_of(self, constrained_primitive: "ConstrainedPrimitive") -> bool:
|
|
1302
|
+
"""
|
|
1303
|
+
Check whether this one is a subclass of ``constrained_primitive``.
|
|
1304
|
+
|
|
1305
|
+
Every constrained primitive is a subclass of itself.
|
|
1306
|
+
"""
|
|
1307
|
+
# NOTE (mristin, 2022-05-13):
|
|
1308
|
+
# This function is not used by the aas-core-codegen, but by downstream clients
|
|
1309
|
+
# such as aas-core3.0rc02-testgen.
|
|
1310
|
+
|
|
1311
|
+
if id(constrained_primitive) == id(self):
|
|
1312
|
+
return True
|
|
1313
|
+
|
|
1314
|
+
return id(constrained_primitive) in self._ancestor_id_set
|
|
1315
|
+
|
|
1316
|
+
@property
|
|
1317
|
+
def descendant_id_set(self) -> FrozenSet[int]:
|
|
1318
|
+
"""List the IDs (as in Python's ``id`` built-in) of the descendants."""
|
|
1319
|
+
return self._descendant_id_set
|
|
1320
|
+
|
|
1321
|
+
@property
|
|
1322
|
+
def invariants(self) -> Sequence[Invariant]:
|
|
1323
|
+
"""List invariants of the class."""
|
|
1324
|
+
return self._invariants
|
|
1325
|
+
|
|
1326
|
+
@property
|
|
1327
|
+
def invariant_id_set(self) -> FrozenSet[int]:
|
|
1328
|
+
"""Collect IDs (with :py:func:`id`) of the invariant objects in a set."""
|
|
1329
|
+
return self._invariant_id_set
|
|
1330
|
+
|
|
1331
|
+
def __repr__(self) -> str:
|
|
1332
|
+
"""Represent the instance as a string for easier debugging."""
|
|
1333
|
+
return (
|
|
1334
|
+
f"<{_MODULE_NAME}.{self.__class__.__name__} {self.name} at 0x{id(self):x}>"
|
|
1335
|
+
)
|
|
1336
|
+
|
|
1337
|
+
|
|
1338
|
+
class Class(DBC):
|
|
1339
|
+
"""Represent an abstract or a concrete class."""
|
|
1340
|
+
|
|
1341
|
+
#: Name of the class
|
|
1342
|
+
name: Final[Identifier]
|
|
1343
|
+
|
|
1344
|
+
# region Inheritances
|
|
1345
|
+
|
|
1346
|
+
# NOTE (mristin, 2021-12-24):
|
|
1347
|
+
# We have to decorate inheritances with ``@property`` so that the translation code
|
|
1348
|
+
# is forced to use ``_set_inheritances``.
|
|
1349
|
+
|
|
1350
|
+
_inheritances: Sequence["ClassUnion"]
|
|
1351
|
+
|
|
1352
|
+
_inheritance_id_set: FrozenSet[int]
|
|
1353
|
+
|
|
1354
|
+
# endregion
|
|
1355
|
+
|
|
1356
|
+
# region Ancestors
|
|
1357
|
+
|
|
1358
|
+
# NOTE (mristin, 2023-03-17):
|
|
1359
|
+
# We have to decorate ancestors with ``@property`` so that the translation code
|
|
1360
|
+
# is forced to use ``_set_ancestors``.
|
|
1361
|
+
|
|
1362
|
+
_ancestors: Sequence["ClassUnion"]
|
|
1363
|
+
|
|
1364
|
+
_ancestor_id_set: FrozenSet[int]
|
|
1365
|
+
|
|
1366
|
+
# endregion
|
|
1367
|
+
|
|
1368
|
+
#: If set, this class is implementation-specific, and we need to provide a snippet
|
|
1369
|
+
#: for each implementation target
|
|
1370
|
+
is_implementation_specific: Final[bool]
|
|
1371
|
+
|
|
1372
|
+
#: Interface of the class. If it is a concrete class with no descendants, there is
|
|
1373
|
+
#: no interface available.
|
|
1374
|
+
interface: Optional["Interface"]
|
|
1375
|
+
|
|
1376
|
+
# region Descendants
|
|
1377
|
+
|
|
1378
|
+
# NOTE (mristin, 2023-03-24):
|
|
1379
|
+
# We have to decorate ``descendant_id_set``, ``descendants``,
|
|
1380
|
+
# ``concrete_descendant_id_set`` and ``concrete_descendants`` with
|
|
1381
|
+
# ``@property`` so that the translation code is forced to use
|
|
1382
|
+
# ``_set_descendants``.
|
|
1383
|
+
|
|
1384
|
+
_descendant_id_set: FrozenSet[int]
|
|
1385
|
+
|
|
1386
|
+
_descendants: Sequence["ClassUnion"]
|
|
1387
|
+
|
|
1388
|
+
_concrete_descendant_id_set: FrozenSet[int]
|
|
1389
|
+
|
|
1390
|
+
_concrete_descendants: Sequence["ConcreteClass"]
|
|
1391
|
+
|
|
1392
|
+
# endregion
|
|
1393
|
+
|
|
1394
|
+
# region Properties
|
|
1395
|
+
|
|
1396
|
+
# NOTE (mristin, 2022-03-19):
|
|
1397
|
+
# We have to decorate properties with ``@property`` so that the translation code
|
|
1398
|
+
# is forced to use ``_set_properties``.
|
|
1399
|
+
|
|
1400
|
+
_properties: Sequence[Property]
|
|
1401
|
+
|
|
1402
|
+
_properties_by_name: Mapping[Identifier, Property]
|
|
1403
|
+
|
|
1404
|
+
_property_id_set: FrozenSet[int]
|
|
1405
|
+
|
|
1406
|
+
# endregion
|
|
1407
|
+
|
|
1408
|
+
# region Methods
|
|
1409
|
+
|
|
1410
|
+
# NOTE (mristin, 2022-03-19):
|
|
1411
|
+
# We have to decorate methods with ``@property`` so that the translation code
|
|
1412
|
+
# is forced to use ``_set_methods``.
|
|
1413
|
+
|
|
1414
|
+
_methods: Sequence["MethodUnion"]
|
|
1415
|
+
|
|
1416
|
+
_methods_by_name: Mapping[Identifier, "MethodUnion"]
|
|
1417
|
+
|
|
1418
|
+
_method_id_set: FrozenSet[int]
|
|
1419
|
+
|
|
1420
|
+
# endregion
|
|
1421
|
+
|
|
1422
|
+
#: Constructor specification of the class
|
|
1423
|
+
constructor: Final[Constructor]
|
|
1424
|
+
|
|
1425
|
+
# region Invariants
|
|
1426
|
+
|
|
1427
|
+
# NOTE (mristin, 2022-03-19):
|
|
1428
|
+
# We have to decorate invariants with ``@property`` so that the translation code
|
|
1429
|
+
# is forced to use ``_set_invariants``.
|
|
1430
|
+
|
|
1431
|
+
_invariants: Sequence[Invariant]
|
|
1432
|
+
|
|
1433
|
+
_invariant_id_set: FrozenSet[int]
|
|
1434
|
+
|
|
1435
|
+
# endregion
|
|
1436
|
+
|
|
1437
|
+
#: Particular serialization settings for this class
|
|
1438
|
+
serialization: Final[Serialization]
|
|
1439
|
+
|
|
1440
|
+
#: Description of the class
|
|
1441
|
+
description: Final[Optional[DescriptionOfOurType]]
|
|
1442
|
+
|
|
1443
|
+
#: Relation to the class from the parse stage
|
|
1444
|
+
parsed: Final[parse.Class]
|
|
1445
|
+
|
|
1446
|
+
# fmt: off
|
|
1447
|
+
@require(
|
|
1448
|
+
lambda inheritances:
|
|
1449
|
+
len(inheritances) == len(set(inheritance.name for inheritance in inheritances)),
|
|
1450
|
+
"No duplicate inheritances"
|
|
1451
|
+
)
|
|
1452
|
+
# fmt: on
|
|
1453
|
+
def _set_inheritances(self, inheritances: Sequence["ClassUnion"]) -> None:
|
|
1454
|
+
"""
|
|
1455
|
+
Set the inheritances in the class.
|
|
1456
|
+
|
|
1457
|
+
This method is expected to be called only during the translation phase.
|
|
1458
|
+
"""
|
|
1459
|
+
self._inheritances = inheritances
|
|
1460
|
+
|
|
1461
|
+
self._inheritance_id_set = frozenset(
|
|
1462
|
+
id(inheritance) for inheritance in self._inheritances
|
|
1463
|
+
)
|
|
1464
|
+
|
|
1465
|
+
@require(lambda self, ancestors: self not in ancestors)
|
|
1466
|
+
def _set_ancestors(self, ancestors: Sequence["ClassUnion"]) -> None:
|
|
1467
|
+
"""
|
|
1468
|
+
Set the ancestors in the class.
|
|
1469
|
+
|
|
1470
|
+
This method is expected to be called only during the translation phase.
|
|
1471
|
+
"""
|
|
1472
|
+
self._ancestor_id_set = frozenset(id(ancestor) for ancestor in ancestors)
|
|
1473
|
+
|
|
1474
|
+
self._ancestors = ancestors
|
|
1475
|
+
|
|
1476
|
+
@require(lambda self, descendants: self not in descendants)
|
|
1477
|
+
def _set_descendants(self, descendants: Sequence["ClassUnion"]) -> None:
|
|
1478
|
+
"""
|
|
1479
|
+
Set the descendants and the concrete descendants in the class.
|
|
1480
|
+
|
|
1481
|
+
This method is expected to be called only during the translation phase.
|
|
1482
|
+
"""
|
|
1483
|
+
self._descendant_id_set = frozenset(
|
|
1484
|
+
id(descendant) for descendant in descendants
|
|
1485
|
+
)
|
|
1486
|
+
|
|
1487
|
+
self._descendants = descendants
|
|
1488
|
+
|
|
1489
|
+
self._concrete_descendants = [
|
|
1490
|
+
descendant
|
|
1491
|
+
for descendant in descendants
|
|
1492
|
+
if isinstance(descendant, ConcreteClass)
|
|
1493
|
+
]
|
|
1494
|
+
|
|
1495
|
+
self._concrete_descendant_id_set = frozenset(
|
|
1496
|
+
id(descendant) for descendant in self._concrete_descendants
|
|
1497
|
+
)
|
|
1498
|
+
|
|
1499
|
+
# fmt: off
|
|
1500
|
+
@require(
|
|
1501
|
+
lambda properties:
|
|
1502
|
+
len(properties) == len(set(prop.name for prop in properties)),
|
|
1503
|
+
"No duplicate properties"
|
|
1504
|
+
)
|
|
1505
|
+
# fmt: on
|
|
1506
|
+
def _set_properties(self, properties: Sequence[Property]) -> None:
|
|
1507
|
+
"""
|
|
1508
|
+
Set the properties in the class.
|
|
1509
|
+
|
|
1510
|
+
This method is expected to be called only during the translation phase.
|
|
1511
|
+
"""
|
|
1512
|
+
self._properties = properties
|
|
1513
|
+
self._properties_by_name = {prop.name: prop for prop in properties}
|
|
1514
|
+
self._property_id_set = frozenset(id(prop) for prop in properties)
|
|
1515
|
+
|
|
1516
|
+
# fmt: off
|
|
1517
|
+
@require(
|
|
1518
|
+
lambda methods:
|
|
1519
|
+
len(methods) == len(set(method.name for method in methods)),
|
|
1520
|
+
"No duplicate methods"
|
|
1521
|
+
)
|
|
1522
|
+
# fmt: on
|
|
1523
|
+
def _set_methods(self, methods: Sequence["MethodUnion"]) -> None:
|
|
1524
|
+
"""
|
|
1525
|
+
Set the methods in the class.
|
|
1526
|
+
|
|
1527
|
+
This method is expected to be called only during the translation phase.
|
|
1528
|
+
"""
|
|
1529
|
+
self._methods = methods
|
|
1530
|
+
self._methods_by_name = {method.name: method for method in methods}
|
|
1531
|
+
self._method_id_set = frozenset(id(method) for method in methods)
|
|
1532
|
+
|
|
1533
|
+
def _set_invariants(self, invariants: Sequence[Invariant]) -> None:
|
|
1534
|
+
"""
|
|
1535
|
+
Set the invariants in the class.
|
|
1536
|
+
|
|
1537
|
+
This method is expected to be called only during the translation phase.
|
|
1538
|
+
"""
|
|
1539
|
+
self._invariants = invariants
|
|
1540
|
+
self._invariant_id_set = frozenset(id(inv) for inv in invariants)
|
|
1541
|
+
|
|
1542
|
+
# fmt: off
|
|
1543
|
+
@require(
|
|
1544
|
+
lambda ancestors, inheritances:
|
|
1545
|
+
(
|
|
1546
|
+
ancestor_id_set := set(id(ancestor) for ancestor in ancestors),
|
|
1547
|
+
all(
|
|
1548
|
+
id(inheritance) in ancestor_id_set # pylint: disable=used-before-assignment
|
|
1549
|
+
for inheritance in inheritances
|
|
1550
|
+
)
|
|
1551
|
+
)[1],
|
|
1552
|
+
"Inheritances is a subset of ancestors"
|
|
1553
|
+
)
|
|
1554
|
+
@require(
|
|
1555
|
+
lambda ancestors, descendants:
|
|
1556
|
+
len(
|
|
1557
|
+
set(id(ancestor) for ancestor in ancestors).difference(
|
|
1558
|
+
id(descendant) for descendant in descendants
|
|
1559
|
+
)
|
|
1560
|
+
) == 0,
|
|
1561
|
+
"No ancestor is also a descendant"
|
|
1562
|
+
)
|
|
1563
|
+
@require(lambda self, inheritances: self not in inheritances)
|
|
1564
|
+
@require(lambda self, ancestors: self not in ancestors)
|
|
1565
|
+
@require(lambda self, descendants: self not in descendants)
|
|
1566
|
+
@ensure(
|
|
1567
|
+
lambda self:
|
|
1568
|
+
all(
|
|
1569
|
+
isinstance(descendant, ConcreteClass)
|
|
1570
|
+
for descendant in self.concrete_descendants
|
|
1571
|
+
),
|
|
1572
|
+
"All concrete descendants must match in type"
|
|
1573
|
+
)
|
|
1574
|
+
@ensure(
|
|
1575
|
+
lambda descendants, self:
|
|
1576
|
+
all(
|
|
1577
|
+
(
|
|
1578
|
+
id(descendant) in self.concrete_descendant_id_set
|
|
1579
|
+
and descendant in self.descendants
|
|
1580
|
+
)
|
|
1581
|
+
for descendant in descendants
|
|
1582
|
+
),
|
|
1583
|
+
"Descendants are propagated to properties"
|
|
1584
|
+
)
|
|
1585
|
+
@ensure(
|
|
1586
|
+
lambda self:
|
|
1587
|
+
(
|
|
1588
|
+
len(
|
|
1589
|
+
self.concrete_descendant_id_set.intersection(self.descendant_id_set)
|
|
1590
|
+
) == len(self.concrete_descendant_id_set)
|
|
1591
|
+
),
|
|
1592
|
+
"Concrete descendants are a subset of descendants"
|
|
1593
|
+
)
|
|
1594
|
+
@ensure(
|
|
1595
|
+
lambda self:
|
|
1596
|
+
(
|
|
1597
|
+
id(descendant) in self.concrete_descendant_id_set
|
|
1598
|
+
for descendant in self.descendants
|
|
1599
|
+
if isinstance(descendant, ConcreteClass)
|
|
1600
|
+
),
|
|
1601
|
+
"All concrete descendants are in concrete descendant set"
|
|
1602
|
+
)
|
|
1603
|
+
# fmt: on
|
|
1604
|
+
def __init__(
|
|
1605
|
+
self,
|
|
1606
|
+
name: Identifier,
|
|
1607
|
+
inheritances: Sequence["ClassUnion"],
|
|
1608
|
+
ancestors: Sequence["ClassUnion"],
|
|
1609
|
+
interface: Optional["Interface"],
|
|
1610
|
+
descendants: Sequence["ClassUnion"],
|
|
1611
|
+
is_implementation_specific: bool,
|
|
1612
|
+
properties: Sequence[Property],
|
|
1613
|
+
methods: Sequence["MethodUnion"],
|
|
1614
|
+
constructor: Constructor,
|
|
1615
|
+
invariants: Sequence[Invariant],
|
|
1616
|
+
serialization: Serialization,
|
|
1617
|
+
description: Optional[DescriptionOfOurType],
|
|
1618
|
+
parsed: parse.Class,
|
|
1619
|
+
) -> None:
|
|
1620
|
+
"""Initialize with the given values."""
|
|
1621
|
+
self.name = name
|
|
1622
|
+
self._set_inheritances(inheritances)
|
|
1623
|
+
self._set_ancestors(ancestors)
|
|
1624
|
+
self.interface = interface
|
|
1625
|
+
self._set_descendants(descendants)
|
|
1626
|
+
self.is_implementation_specific = is_implementation_specific
|
|
1627
|
+
self._set_properties(properties)
|
|
1628
|
+
self._set_methods(methods)
|
|
1629
|
+
self.constructor = constructor
|
|
1630
|
+
self._set_invariants(invariants)
|
|
1631
|
+
self.serialization = serialization
|
|
1632
|
+
self.description = description
|
|
1633
|
+
self.parsed = parsed
|
|
1634
|
+
|
|
1635
|
+
@property
|
|
1636
|
+
def inheritances(self) -> Sequence["ClassUnion"]:
|
|
1637
|
+
"""Return direct parents that this class inherits from."""
|
|
1638
|
+
return self._inheritances
|
|
1639
|
+
|
|
1640
|
+
@property
|
|
1641
|
+
def inheritance_id_set(self) -> FrozenSet[int]:
|
|
1642
|
+
"""Collect IDs (with :py:func:`id`) of the inheritance objects in a set."""
|
|
1643
|
+
return self._inheritance_id_set
|
|
1644
|
+
|
|
1645
|
+
@property
|
|
1646
|
+
def ancestors(self) -> Sequence["ClassUnion"]:
|
|
1647
|
+
"""Return classes that this class directly or indirectly inherits from."""
|
|
1648
|
+
return self._ancestors
|
|
1649
|
+
|
|
1650
|
+
@property
|
|
1651
|
+
def ancestor_id_set(self) -> FrozenSet[int]:
|
|
1652
|
+
"""Collect IDs (with :py:func:`id`) of the ancestor classes in a set."""
|
|
1653
|
+
return self._ancestor_id_set
|
|
1654
|
+
|
|
1655
|
+
def is_subclass_of(self, cls: "ClassUnion") -> bool:
|
|
1656
|
+
"""
|
|
1657
|
+
Check whether this class is a subclass of ``cls``.
|
|
1658
|
+
|
|
1659
|
+
Every class is a subclass of itself.
|
|
1660
|
+
"""
|
|
1661
|
+
# NOTE (mristin, 2022-05-13):
|
|
1662
|
+
# This function is not used by the aas-core-codegen, but by downstream clients
|
|
1663
|
+
# such as aas-core3.0rc02-testgen.
|
|
1664
|
+
|
|
1665
|
+
if id(cls) == id(self):
|
|
1666
|
+
return True
|
|
1667
|
+
|
|
1668
|
+
return id(cls) in self._ancestor_id_set
|
|
1669
|
+
|
|
1670
|
+
@property
|
|
1671
|
+
def descendant_id_set(self) -> FrozenSet[int]:
|
|
1672
|
+
"""List the IDs (as in Python's ``id`` built-in) of the descendants."""
|
|
1673
|
+
return self._descendant_id_set
|
|
1674
|
+
|
|
1675
|
+
@property
|
|
1676
|
+
def descendants(self) -> Sequence["ClassUnion"]:
|
|
1677
|
+
"""List all descendants of this class."""
|
|
1678
|
+
return self._descendants
|
|
1679
|
+
|
|
1680
|
+
@property
|
|
1681
|
+
def concrete_descendant_id_set(self) -> FrozenSet[int]:
|
|
1682
|
+
"""List the IDs (as in Python's ``id`` built-in) of the concrete descendants."""
|
|
1683
|
+
return self._concrete_descendant_id_set
|
|
1684
|
+
|
|
1685
|
+
@property
|
|
1686
|
+
def concrete_descendants(self) -> Sequence["ConcreteClass"]:
|
|
1687
|
+
"""List descendants of this class which are concrete classes."""
|
|
1688
|
+
return self._concrete_descendants
|
|
1689
|
+
|
|
1690
|
+
@property
|
|
1691
|
+
def properties(self) -> Sequence[Property]:
|
|
1692
|
+
"""Return list of properties of the class."""
|
|
1693
|
+
return self._properties
|
|
1694
|
+
|
|
1695
|
+
@property
|
|
1696
|
+
def properties_by_name(self) -> Mapping[Identifier, Property]:
|
|
1697
|
+
"""Map all properties by their names."""
|
|
1698
|
+
return self._properties_by_name
|
|
1699
|
+
|
|
1700
|
+
@property
|
|
1701
|
+
def property_id_set(self) -> FrozenSet[int]:
|
|
1702
|
+
"""Collect IDs (with :py:func:`id`) of the property objects in a set."""
|
|
1703
|
+
return self._property_id_set
|
|
1704
|
+
|
|
1705
|
+
@property
|
|
1706
|
+
def methods(self) -> Sequence["MethodUnion"]:
|
|
1707
|
+
"""
|
|
1708
|
+
List methods of the class.
|
|
1709
|
+
|
|
1710
|
+
The methods are strictly non-static and non-class (in the Python sense of
|
|
1711
|
+
the terms).
|
|
1712
|
+
"""
|
|
1713
|
+
return self._methods
|
|
1714
|
+
|
|
1715
|
+
@property
|
|
1716
|
+
def methods_by_name(self) -> Mapping[Identifier, "MethodUnion"]:
|
|
1717
|
+
"""Map all methods by their names."""
|
|
1718
|
+
return self._methods_by_name
|
|
1719
|
+
|
|
1720
|
+
@property
|
|
1721
|
+
def method_id_set(self) -> FrozenSet[int]:
|
|
1722
|
+
"""Collect IDs (with :py:func:`id`) of the method objects in a set."""
|
|
1723
|
+
return self._method_id_set
|
|
1724
|
+
|
|
1725
|
+
@property
|
|
1726
|
+
def invariants(self) -> Sequence[Invariant]:
|
|
1727
|
+
"""List invariants of the class."""
|
|
1728
|
+
return self._invariants
|
|
1729
|
+
|
|
1730
|
+
@property
|
|
1731
|
+
def invariant_id_set(self) -> FrozenSet[int]:
|
|
1732
|
+
"""Collect IDs (with :py:func:`id`) of the invariant objects in a set."""
|
|
1733
|
+
return self._invariant_id_set
|
|
1734
|
+
|
|
1735
|
+
@abc.abstractmethod
|
|
1736
|
+
def __repr__(self) -> str:
|
|
1737
|
+
# Signal that this is a purely abstract class.
|
|
1738
|
+
raise NotImplementedError()
|
|
1739
|
+
|
|
1740
|
+
|
|
1741
|
+
class ConcreteClass(Class):
|
|
1742
|
+
"""Represent a class that can be instantiated."""
|
|
1743
|
+
|
|
1744
|
+
def __repr__(self) -> str:
|
|
1745
|
+
"""Represent the instance as a string for easier debugging."""
|
|
1746
|
+
return (
|
|
1747
|
+
f"<{_MODULE_NAME}.{self.__class__.__name__} {self.name} at 0x{id(self):x}>"
|
|
1748
|
+
)
|
|
1749
|
+
|
|
1750
|
+
|
|
1751
|
+
class AbstractClass(Class):
|
|
1752
|
+
"""Represent a class that is purely abstract and can not be instantiated."""
|
|
1753
|
+
|
|
1754
|
+
#: Interface of the class. All abstract classes have an interface as opposed to
|
|
1755
|
+
#: concrete classes, which only have an interface if there are descendants.
|
|
1756
|
+
interface: "Interface"
|
|
1757
|
+
|
|
1758
|
+
# We need to override the constructor because the ``interface`` is required.
|
|
1759
|
+
def __init__(
|
|
1760
|
+
self,
|
|
1761
|
+
name: Identifier,
|
|
1762
|
+
inheritances: Sequence["ClassUnion"],
|
|
1763
|
+
ancestors: Sequence["ClassUnion"],
|
|
1764
|
+
interface: "Interface",
|
|
1765
|
+
descendants: Sequence["ClassUnion"],
|
|
1766
|
+
is_implementation_specific: bool,
|
|
1767
|
+
properties: Sequence[Property],
|
|
1768
|
+
methods: Sequence["MethodUnion"],
|
|
1769
|
+
constructor: Constructor,
|
|
1770
|
+
invariants: Sequence[Invariant],
|
|
1771
|
+
serialization: Serialization,
|
|
1772
|
+
description: Optional[DescriptionOfOurType],
|
|
1773
|
+
parsed: parse.Class,
|
|
1774
|
+
) -> None:
|
|
1775
|
+
"""Initialize with the given values."""
|
|
1776
|
+
Class.__init__(
|
|
1777
|
+
self,
|
|
1778
|
+
name=name,
|
|
1779
|
+
inheritances=inheritances,
|
|
1780
|
+
ancestors=ancestors,
|
|
1781
|
+
interface=interface,
|
|
1782
|
+
descendants=descendants,
|
|
1783
|
+
is_implementation_specific=is_implementation_specific,
|
|
1784
|
+
properties=properties,
|
|
1785
|
+
methods=methods,
|
|
1786
|
+
constructor=constructor,
|
|
1787
|
+
invariants=invariants,
|
|
1788
|
+
serialization=serialization,
|
|
1789
|
+
description=description,
|
|
1790
|
+
parsed=parsed,
|
|
1791
|
+
)
|
|
1792
|
+
|
|
1793
|
+
def __repr__(self) -> str:
|
|
1794
|
+
"""Represent the instance as a string for easier debugging."""
|
|
1795
|
+
return (
|
|
1796
|
+
f"<{_MODULE_NAME}.{self.__class__.__name__} {self.name} at 0x{id(self):x}>"
|
|
1797
|
+
)
|
|
1798
|
+
|
|
1799
|
+
|
|
1800
|
+
# endregion
|
|
1801
|
+
|
|
1802
|
+
|
|
1803
|
+
# region Constants
|
|
1804
|
+
|
|
1805
|
+
|
|
1806
|
+
class Constant(DBC):
|
|
1807
|
+
"""Represent a constant of the meta-model."""
|
|
1808
|
+
|
|
1809
|
+
#: Name of the constant
|
|
1810
|
+
name: Final[Identifier]
|
|
1811
|
+
|
|
1812
|
+
#: Description of the constant, if any given in the meta-model
|
|
1813
|
+
description: Final[Optional[DescriptionOfConstant]]
|
|
1814
|
+
|
|
1815
|
+
def __init__(
|
|
1816
|
+
self,
|
|
1817
|
+
name: Identifier,
|
|
1818
|
+
description: Optional[DescriptionOfConstant],
|
|
1819
|
+
) -> None:
|
|
1820
|
+
"""Initialize with the given values."""
|
|
1821
|
+
self.name = name
|
|
1822
|
+
self.description = description
|
|
1823
|
+
|
|
1824
|
+
@abc.abstractmethod
|
|
1825
|
+
def __repr__(self) -> str:
|
|
1826
|
+
"""Represent the instance as a string for easier debugging."""
|
|
1827
|
+
raise NotImplementedError()
|
|
1828
|
+
|
|
1829
|
+
|
|
1830
|
+
class ConstantPrimitive(Constant):
|
|
1831
|
+
"""Represent a constant primitive value in the meta-model."""
|
|
1832
|
+
|
|
1833
|
+
#: Value of the constant
|
|
1834
|
+
value: Union[bool, int, float, str, bytearray]
|
|
1835
|
+
|
|
1836
|
+
#: Type of the constant
|
|
1837
|
+
a_type: Final[PrimitiveType]
|
|
1838
|
+
|
|
1839
|
+
#: Relation to the parse stage
|
|
1840
|
+
parsed: Final[parse.ConstantPrimitive]
|
|
1841
|
+
|
|
1842
|
+
# fmt: off
|
|
1843
|
+
# noinspection PyTypeHints
|
|
1844
|
+
@require(
|
|
1845
|
+
lambda value, a_type:
|
|
1846
|
+
isinstance(value, PRIMITIVE_TYPE_TO_PYTHON_TYPE[a_type])
|
|
1847
|
+
)
|
|
1848
|
+
# fmt: on
|
|
1849
|
+
def __init__(
|
|
1850
|
+
self,
|
|
1851
|
+
name: Identifier,
|
|
1852
|
+
value: Union[bool, int, float, str, bytearray],
|
|
1853
|
+
a_type: PrimitiveType,
|
|
1854
|
+
description: Optional[DescriptionOfConstant],
|
|
1855
|
+
parsed: parse.ConstantPrimitive,
|
|
1856
|
+
) -> None:
|
|
1857
|
+
"""Initialize with the given values."""
|
|
1858
|
+
Constant.__init__(
|
|
1859
|
+
self,
|
|
1860
|
+
name=name,
|
|
1861
|
+
description=description,
|
|
1862
|
+
)
|
|
1863
|
+
|
|
1864
|
+
self.value = value
|
|
1865
|
+
self.a_type = a_type
|
|
1866
|
+
self.parsed = parsed
|
|
1867
|
+
|
|
1868
|
+
def __repr__(self) -> str:
|
|
1869
|
+
"""Represent the instance as a string for easier debugging."""
|
|
1870
|
+
return (
|
|
1871
|
+
f"<{_MODULE_NAME}.{self.__class__.__name__} {self.name} at 0x{id(self):x}>"
|
|
1872
|
+
)
|
|
1873
|
+
|
|
1874
|
+
|
|
1875
|
+
class PrimitiveSetLiteral:
|
|
1876
|
+
"""Represent an item of a set of primitive literals."""
|
|
1877
|
+
|
|
1878
|
+
#: Value of the literal
|
|
1879
|
+
value: Union[bool, int, float, str, bytearray]
|
|
1880
|
+
|
|
1881
|
+
#: Type of the literal
|
|
1882
|
+
a_type: Final[PrimitiveType]
|
|
1883
|
+
|
|
1884
|
+
#: Relation to the parse stage
|
|
1885
|
+
parsed: Final[parse.SetLiteral]
|
|
1886
|
+
|
|
1887
|
+
# fmt: off
|
|
1888
|
+
# noinspection PyTypeHints
|
|
1889
|
+
@require(
|
|
1890
|
+
lambda value, a_type:
|
|
1891
|
+
isinstance(value, PRIMITIVE_TYPE_TO_PYTHON_TYPE[a_type])
|
|
1892
|
+
)
|
|
1893
|
+
# fmt: on
|
|
1894
|
+
def __init__(
|
|
1895
|
+
self,
|
|
1896
|
+
value: Union[bool, int, float, str, bytearray],
|
|
1897
|
+
a_type: PrimitiveType,
|
|
1898
|
+
parsed: parse.SetLiteral,
|
|
1899
|
+
) -> None:
|
|
1900
|
+
"""Initialize with the given values."""
|
|
1901
|
+
self.value = value
|
|
1902
|
+
self.a_type = a_type
|
|
1903
|
+
self.parsed = parsed
|
|
1904
|
+
|
|
1905
|
+
def __repr__(self) -> str:
|
|
1906
|
+
"""Represent as a string for easier debugging."""
|
|
1907
|
+
return (
|
|
1908
|
+
f"<{_MODULE_NAME}.{self.__class__.__name__} "
|
|
1909
|
+
f"{self.a_type.name} {self.value!r} at 0x{id(self):x}>"
|
|
1910
|
+
)
|
|
1911
|
+
|
|
1912
|
+
|
|
1913
|
+
class ConstantSetOfPrimitives(Constant):
|
|
1914
|
+
"""Represent a set of primitive literals."""
|
|
1915
|
+
|
|
1916
|
+
#: Type of the literals
|
|
1917
|
+
a_type: Final[PrimitiveType]
|
|
1918
|
+
|
|
1919
|
+
#: Members of this subset
|
|
1920
|
+
literals: Final[Sequence[PrimitiveSetLiteral]]
|
|
1921
|
+
|
|
1922
|
+
#: All other subsets which are contained in this enumeration subset
|
|
1923
|
+
subsets: Final[Sequence["ConstantSetOfPrimitives"]]
|
|
1924
|
+
|
|
1925
|
+
#: Relation to the parse stage
|
|
1926
|
+
parsed: Final[parse.ConstantSet]
|
|
1927
|
+
|
|
1928
|
+
#: Set of all the literal values
|
|
1929
|
+
literal_value_set: Final[Set[Union[bool, int, float, str, bytearray]]]
|
|
1930
|
+
|
|
1931
|
+
# fmt: off
|
|
1932
|
+
# noinspection PyTypeHints
|
|
1933
|
+
@require(
|
|
1934
|
+
lambda a_type, literals:
|
|
1935
|
+
all(
|
|
1936
|
+
literal.a_type is a_type
|
|
1937
|
+
for literal in literals
|
|
1938
|
+
),
|
|
1939
|
+
"All literals share the same primitive type"
|
|
1940
|
+
)
|
|
1941
|
+
@ensure(
|
|
1942
|
+
lambda self:
|
|
1943
|
+
not (len(self.literal_value_set) > 1)
|
|
1944
|
+
or (
|
|
1945
|
+
python_type := PRIMITIVE_TYPE_TO_PYTHON_TYPE[self.a_type],
|
|
1946
|
+
all(
|
|
1947
|
+
isinstance(value, python_type) # pylint: disable=used-before-assignment
|
|
1948
|
+
for value in self.literal_value_set
|
|
1949
|
+
)
|
|
1950
|
+
)[1],
|
|
1951
|
+
"Types in the literal value set match ``a_type``"
|
|
1952
|
+
)
|
|
1953
|
+
# fmt: on
|
|
1954
|
+
def __init__(
|
|
1955
|
+
self,
|
|
1956
|
+
name: Identifier,
|
|
1957
|
+
a_type: PrimitiveType,
|
|
1958
|
+
literals: Sequence[PrimitiveSetLiteral],
|
|
1959
|
+
subsets: Sequence["ConstantSetOfPrimitives"],
|
|
1960
|
+
description: Optional[DescriptionOfConstant],
|
|
1961
|
+
parsed: parse.ConstantSet,
|
|
1962
|
+
) -> None:
|
|
1963
|
+
"""Initialize with the given values."""
|
|
1964
|
+
Constant.__init__(
|
|
1965
|
+
self,
|
|
1966
|
+
name=name,
|
|
1967
|
+
description=description,
|
|
1968
|
+
)
|
|
1969
|
+
|
|
1970
|
+
self.a_type = a_type
|
|
1971
|
+
self.literals = literals
|
|
1972
|
+
self.subsets = subsets
|
|
1973
|
+
self.parsed = parsed
|
|
1974
|
+
|
|
1975
|
+
self.literal_value_set = {literal.value for literal in literals}
|
|
1976
|
+
|
|
1977
|
+
def __repr__(self) -> str:
|
|
1978
|
+
"""Represent the instance as a string for easier debugging."""
|
|
1979
|
+
return (
|
|
1980
|
+
f"<{_MODULE_NAME}.{self.__class__.__name__} {self.name} at 0x{id(self):x}>"
|
|
1981
|
+
)
|
|
1982
|
+
|
|
1983
|
+
|
|
1984
|
+
class ConstantSetOfEnumerationLiterals(Constant):
|
|
1985
|
+
"""Represent a set of enumeration literals."""
|
|
1986
|
+
|
|
1987
|
+
#: Enumeration that this is a subset of
|
|
1988
|
+
enumeration: Final[Enumeration]
|
|
1989
|
+
|
|
1990
|
+
#: Members of this subset
|
|
1991
|
+
literals: Final[Sequence[EnumerationLiteral]]
|
|
1992
|
+
|
|
1993
|
+
#: All other subsets which are contained in this enumeration subset
|
|
1994
|
+
subsets: Final[Sequence["ConstantSetOfEnumerationLiterals"]]
|
|
1995
|
+
|
|
1996
|
+
#: Relation to the parse stage
|
|
1997
|
+
parsed: Final[parse.ConstantSet]
|
|
1998
|
+
|
|
1999
|
+
#: Set of all the IDs (as in Python objects) of the literals
|
|
2000
|
+
literal_id_set: Final[Set[int]]
|
|
2001
|
+
|
|
2002
|
+
# fmt: off
|
|
2003
|
+
@require(
|
|
2004
|
+
lambda literals, enumeration:
|
|
2005
|
+
all(
|
|
2006
|
+
id(literal) in enumeration.literal_id_set
|
|
2007
|
+
for literal in literals
|
|
2008
|
+
),
|
|
2009
|
+
"All literals are members of the same enumeration"
|
|
2010
|
+
)
|
|
2011
|
+
@ensure(
|
|
2012
|
+
lambda literals, self:
|
|
2013
|
+
all(
|
|
2014
|
+
id(literal) in self.literal_id_set
|
|
2015
|
+
for literal in self.literals
|
|
2016
|
+
) and len(self.literals) == len(self.literal_id_set),
|
|
2017
|
+
"Literal set corresponds to literals"
|
|
2018
|
+
)
|
|
2019
|
+
# fmt: on
|
|
2020
|
+
def __init__(
|
|
2021
|
+
self,
|
|
2022
|
+
name: Identifier,
|
|
2023
|
+
enumeration: Enumeration,
|
|
2024
|
+
literals: Sequence[EnumerationLiteral],
|
|
2025
|
+
subsets: Sequence["ConstantSetOfEnumerationLiterals"],
|
|
2026
|
+
description: Optional[DescriptionOfConstant],
|
|
2027
|
+
parsed: parse.ConstantSet,
|
|
2028
|
+
) -> None:
|
|
2029
|
+
"""Initialize with the given values."""
|
|
2030
|
+
Constant.__init__(
|
|
2031
|
+
self,
|
|
2032
|
+
name=name,
|
|
2033
|
+
description=description,
|
|
2034
|
+
)
|
|
2035
|
+
|
|
2036
|
+
self.enumeration = enumeration
|
|
2037
|
+
self.literals = literals
|
|
2038
|
+
self.subsets = subsets
|
|
2039
|
+
self.parsed = parsed
|
|
2040
|
+
|
|
2041
|
+
self.literal_id_set = {id(literal) for literal in self.literals}
|
|
2042
|
+
|
|
2043
|
+
def __repr__(self) -> str:
|
|
2044
|
+
"""Represent the instance as a string for easier debugging."""
|
|
2045
|
+
return (
|
|
2046
|
+
f"<{_MODULE_NAME}.{self.__class__.__name__} {self.name} at 0x{id(self):x}>"
|
|
2047
|
+
)
|
|
2048
|
+
|
|
2049
|
+
|
|
2050
|
+
# endregion
|
|
2051
|
+
|
|
2052
|
+
# region Verification functions
|
|
2053
|
+
|
|
2054
|
+
|
|
2055
|
+
class Verification(SignatureLike):
|
|
2056
|
+
"""Represent a verification function defined in the meta-model."""
|
|
2057
|
+
|
|
2058
|
+
parsed: parse.Method
|
|
2059
|
+
|
|
2060
|
+
# fmt: off
|
|
2061
|
+
@require(
|
|
2062
|
+
lambda arguments, contracts:
|
|
2063
|
+
(
|
|
2064
|
+
arg_set := {arg.name for arg in arguments},
|
|
2065
|
+
all(
|
|
2066
|
+
arg in arg_set # pylint: disable=used-before-assignment
|
|
2067
|
+
for precondition in contracts.preconditions
|
|
2068
|
+
for arg in precondition.args
|
|
2069
|
+
)
|
|
2070
|
+
and all(
|
|
2071
|
+
arg in arg_set
|
|
2072
|
+
for postcondition in contracts.postconditions
|
|
2073
|
+
for arg in postcondition.args
|
|
2074
|
+
if arg not in ('OLD', 'result')
|
|
2075
|
+
)
|
|
2076
|
+
and all(
|
|
2077
|
+
arg in arg_set
|
|
2078
|
+
for snapshot in contracts.snapshots
|
|
2079
|
+
for arg in snapshot.args
|
|
2080
|
+
)
|
|
2081
|
+
)[1],
|
|
2082
|
+
"All arguments of contracts defined in function arguments"
|
|
2083
|
+
)
|
|
2084
|
+
# fmt: on
|
|
2085
|
+
def __init__(
|
|
2086
|
+
self,
|
|
2087
|
+
name: Identifier,
|
|
2088
|
+
arguments: Sequence[Argument],
|
|
2089
|
+
returns: Optional[TypeAnnotationUnion],
|
|
2090
|
+
description: Optional[DescriptionOfSignature],
|
|
2091
|
+
contracts: Contracts,
|
|
2092
|
+
parsed: parse.Method,
|
|
2093
|
+
) -> None:
|
|
2094
|
+
"""Initialize with the given values."""
|
|
2095
|
+
SignatureLike.__init__(
|
|
2096
|
+
self,
|
|
2097
|
+
name=name,
|
|
2098
|
+
arguments=arguments,
|
|
2099
|
+
returns=returns,
|
|
2100
|
+
description=description,
|
|
2101
|
+
contracts=contracts,
|
|
2102
|
+
parsed=parsed,
|
|
2103
|
+
)
|
|
2104
|
+
|
|
2105
|
+
@abc.abstractmethod
|
|
2106
|
+
def __repr__(self) -> str:
|
|
2107
|
+
# Signal that this is a pure abstract class.
|
|
2108
|
+
raise NotImplementedError()
|
|
2109
|
+
|
|
2110
|
+
|
|
2111
|
+
class ImplementationSpecificVerification(Verification):
|
|
2112
|
+
"""Represent an implementation-specific verification function."""
|
|
2113
|
+
|
|
2114
|
+
def __init__(
|
|
2115
|
+
self,
|
|
2116
|
+
name: Identifier,
|
|
2117
|
+
arguments: Sequence[Argument],
|
|
2118
|
+
returns: Optional[TypeAnnotationUnion],
|
|
2119
|
+
description: Optional[DescriptionOfSignature],
|
|
2120
|
+
contracts: Contracts,
|
|
2121
|
+
parsed: parse.Method,
|
|
2122
|
+
) -> None:
|
|
2123
|
+
"""Initialize with the given values."""
|
|
2124
|
+
Verification.__init__(
|
|
2125
|
+
self,
|
|
2126
|
+
name=name,
|
|
2127
|
+
arguments=arguments,
|
|
2128
|
+
returns=returns,
|
|
2129
|
+
description=description,
|
|
2130
|
+
contracts=contracts,
|
|
2131
|
+
parsed=parsed,
|
|
2132
|
+
)
|
|
2133
|
+
|
|
2134
|
+
def __repr__(self) -> str:
|
|
2135
|
+
"""Represent the instance as a string for easier debugging."""
|
|
2136
|
+
return (
|
|
2137
|
+
f"<{_MODULE_NAME}.{self.__class__.__name__} {self.name} at 0x{id(self):x}>"
|
|
2138
|
+
)
|
|
2139
|
+
|
|
2140
|
+
|
|
2141
|
+
class PatternVerification(Verification):
|
|
2142
|
+
"""
|
|
2143
|
+
Represent a function that checks a string against a regular expression.
|
|
2144
|
+
|
|
2145
|
+
There is expected to be a single string argument (the text to be matched).
|
|
2146
|
+
The function is expected to return a boolean.
|
|
2147
|
+
"""
|
|
2148
|
+
|
|
2149
|
+
#: Method as we understood it in the parse stage
|
|
2150
|
+
parsed: parse.UnderstoodMethod
|
|
2151
|
+
|
|
2152
|
+
#: Pattern, *i.e.* the regular expression, that the function checks against
|
|
2153
|
+
pattern: Final[str]
|
|
2154
|
+
|
|
2155
|
+
#: Expression extracted from the function body to be checked at the end
|
|
2156
|
+
pattern_expr: Final[parse_tree.Expression]
|
|
2157
|
+
|
|
2158
|
+
# fmt: off
|
|
2159
|
+
@require(
|
|
2160
|
+
lambda arguments:
|
|
2161
|
+
len(arguments) == 1
|
|
2162
|
+
and isinstance(arguments[0].type_annotation, PrimitiveTypeAnnotation)
|
|
2163
|
+
and arguments[0].type_annotation.a_type == PrimitiveType.STR,
|
|
2164
|
+
"There is a single string argument"
|
|
2165
|
+
)
|
|
2166
|
+
@require(
|
|
2167
|
+
lambda returns:
|
|
2168
|
+
(returns is not None)
|
|
2169
|
+
and isinstance(returns, PrimitiveTypeAnnotation)
|
|
2170
|
+
and returns.a_type == PrimitiveType.BOOL
|
|
2171
|
+
)
|
|
2172
|
+
# fmt: on
|
|
2173
|
+
def __init__(
|
|
2174
|
+
self,
|
|
2175
|
+
name: Identifier,
|
|
2176
|
+
arguments: Sequence[Argument],
|
|
2177
|
+
returns: Optional[TypeAnnotationUnion],
|
|
2178
|
+
description: Optional[DescriptionOfSignature],
|
|
2179
|
+
contracts: Contracts,
|
|
2180
|
+
pattern: str,
|
|
2181
|
+
parsed: parse.UnderstoodMethod,
|
|
2182
|
+
) -> None:
|
|
2183
|
+
"""Initialize with the given values."""
|
|
2184
|
+
Verification.__init__(
|
|
2185
|
+
self,
|
|
2186
|
+
name=name,
|
|
2187
|
+
arguments=arguments,
|
|
2188
|
+
returns=returns,
|
|
2189
|
+
description=description,
|
|
2190
|
+
contracts=contracts,
|
|
2191
|
+
parsed=parsed,
|
|
2192
|
+
)
|
|
2193
|
+
|
|
2194
|
+
self.pattern = pattern
|
|
2195
|
+
self.pattern_expr = PatternVerification._extract_pattern_expr(parsed.body)
|
|
2196
|
+
|
|
2197
|
+
@staticmethod
|
|
2198
|
+
def _extract_pattern_expr(body: Sequence[parse_tree.Node]) -> parse_tree.Expression:
|
|
2199
|
+
"""Extract the pattern expression from the body of the pattern verification."""
|
|
2200
|
+
assert len(body) >= 1
|
|
2201
|
+
|
|
2202
|
+
assert isinstance(body[-1], parse_tree.Return)
|
|
2203
|
+
# noinspection PyUnresolvedReferences
|
|
2204
|
+
assert isinstance(body[-1].value, parse_tree.IsNotNone)
|
|
2205
|
+
# noinspection PyUnresolvedReferences
|
|
2206
|
+
assert isinstance(body[-1].value.value, parse_tree.FunctionCall)
|
|
2207
|
+
# noinspection PyUnresolvedReferences
|
|
2208
|
+
assert body[-1].value.value.name.identifier == "match"
|
|
2209
|
+
|
|
2210
|
+
# noinspection PyUnresolvedReferences
|
|
2211
|
+
match_call = body[-1].value.value
|
|
2212
|
+
|
|
2213
|
+
assert isinstance(
|
|
2214
|
+
match_call, parse_tree.FunctionCall
|
|
2215
|
+
), f"{parse_tree.dump(match_call)}"
|
|
2216
|
+
assert match_call.name.identifier == "match"
|
|
2217
|
+
|
|
2218
|
+
assert isinstance(match_call.args[0], parse_tree.Expression)
|
|
2219
|
+
return match_call.args[0]
|
|
2220
|
+
|
|
2221
|
+
def __repr__(self) -> str:
|
|
2222
|
+
"""Represent the instance as a string for easier debugging."""
|
|
2223
|
+
return (
|
|
2224
|
+
f"<{_MODULE_NAME}.{self.__class__.__name__} {self.name} at 0x{id(self):x}>"
|
|
2225
|
+
)
|
|
2226
|
+
|
|
2227
|
+
|
|
2228
|
+
class TranspilableVerification(Verification):
|
|
2229
|
+
"""
|
|
2230
|
+
Represent a function that needs to be transpiled into the native code.
|
|
2231
|
+
|
|
2232
|
+
Unlike :class:`.PatternVerification`, we do not understand this verification
|
|
2233
|
+
function at the higher level, and can not use it further in the inference.
|
|
2234
|
+
Nevertheless, we can still transpile it into different target implementations.
|
|
2235
|
+
"""
|
|
2236
|
+
|
|
2237
|
+
#: Method as we understood it in the parse stage
|
|
2238
|
+
parsed: parse.UnderstoodMethod
|
|
2239
|
+
|
|
2240
|
+
def __init__(
|
|
2241
|
+
self,
|
|
2242
|
+
name: Identifier,
|
|
2243
|
+
arguments: Sequence[Argument],
|
|
2244
|
+
returns: Optional[TypeAnnotationUnion],
|
|
2245
|
+
description: Optional[DescriptionOfSignature],
|
|
2246
|
+
contracts: Contracts,
|
|
2247
|
+
parsed: parse.UnderstoodMethod,
|
|
2248
|
+
) -> None:
|
|
2249
|
+
"""Initialize with the given values."""
|
|
2250
|
+
Verification.__init__(
|
|
2251
|
+
self,
|
|
2252
|
+
name=name,
|
|
2253
|
+
arguments=arguments,
|
|
2254
|
+
returns=returns,
|
|
2255
|
+
description=description,
|
|
2256
|
+
contracts=contracts,
|
|
2257
|
+
parsed=parsed,
|
|
2258
|
+
)
|
|
2259
|
+
|
|
2260
|
+
def __repr__(self) -> str:
|
|
2261
|
+
"""Represent the instance as a string for easier debugging."""
|
|
2262
|
+
return (
|
|
2263
|
+
f"<{_MODULE_NAME}.{self.__class__.__name__} {self.name} at 0x{id(self):x}>"
|
|
2264
|
+
)
|
|
2265
|
+
|
|
2266
|
+
|
|
2267
|
+
# endregion
|
|
2268
|
+
|
|
2269
|
+
|
|
2270
|
+
class Signature(SignatureLike):
|
|
2271
|
+
"""Represent a signature of a method in an interface."""
|
|
2272
|
+
|
|
2273
|
+
def __init__(
|
|
2274
|
+
self,
|
|
2275
|
+
name: Identifier,
|
|
2276
|
+
arguments: Sequence[Argument],
|
|
2277
|
+
returns: Optional[TypeAnnotationUnion],
|
|
2278
|
+
description: Optional[DescriptionOfSignature],
|
|
2279
|
+
contracts: Contracts,
|
|
2280
|
+
parsed: parse.Method,
|
|
2281
|
+
) -> None:
|
|
2282
|
+
"""
|
|
2283
|
+
Initialize with the given values.
|
|
2284
|
+
|
|
2285
|
+
The ``parsed`` refers to the method of the abstract or concrete class that
|
|
2286
|
+
defines the interface. Mind that we do not introduce interfaces as a concept
|
|
2287
|
+
in the meta-model.
|
|
2288
|
+
"""
|
|
2289
|
+
SignatureLike.__init__(
|
|
2290
|
+
self,
|
|
2291
|
+
name=name,
|
|
2292
|
+
arguments=arguments,
|
|
2293
|
+
returns=returns,
|
|
2294
|
+
description=description,
|
|
2295
|
+
contracts=contracts,
|
|
2296
|
+
parsed=parsed,
|
|
2297
|
+
)
|
|
2298
|
+
|
|
2299
|
+
def __repr__(self) -> str:
|
|
2300
|
+
"""Represent the instance as a string for easier debugging."""
|
|
2301
|
+
return (
|
|
2302
|
+
f"<{_MODULE_NAME}.{self.__class__.__name__} {self.name} at 0x{id(self):x}>"
|
|
2303
|
+
)
|
|
2304
|
+
|
|
2305
|
+
|
|
2306
|
+
class Interface:
|
|
2307
|
+
"""
|
|
2308
|
+
Represent an interface of some abstract and/or concrete classes.
|
|
2309
|
+
|
|
2310
|
+
Mind that the concept of interfaces is *not* used in the meta-model. We introduce
|
|
2311
|
+
it at the intermediate stage to facilitate generation of the code, especially for
|
|
2312
|
+
targets where multiple inheritance is not supported.
|
|
2313
|
+
"""
|
|
2314
|
+
|
|
2315
|
+
#: Class which this interface is based on
|
|
2316
|
+
base: Final["ClassUnion"]
|
|
2317
|
+
|
|
2318
|
+
#: Name of the interface
|
|
2319
|
+
name: Final[Identifier]
|
|
2320
|
+
|
|
2321
|
+
inheritances: Final[Sequence["Interface"]]
|
|
2322
|
+
|
|
2323
|
+
#: List of concrete classes that implement this interface
|
|
2324
|
+
implementers: Sequence["ConcreteClass"]
|
|
2325
|
+
|
|
2326
|
+
#: List of properties assumed by the interface
|
|
2327
|
+
properties: Final[Sequence[Property]]
|
|
2328
|
+
|
|
2329
|
+
#: List of method signatures assumed by the interface
|
|
2330
|
+
signatures: Final[Sequence[Signature]]
|
|
2331
|
+
|
|
2332
|
+
#: Description of the interface, taken from class
|
|
2333
|
+
description: Final[Optional[DescriptionOfOurType]]
|
|
2334
|
+
|
|
2335
|
+
#: Relation to the class from the parse stage
|
|
2336
|
+
parsed: Final[parse.Class]
|
|
2337
|
+
|
|
2338
|
+
#: Map all properties by their identifiers to the corresponding objects
|
|
2339
|
+
properties_by_name: Final[Mapping[Identifier, Property]]
|
|
2340
|
+
|
|
2341
|
+
#: Collect IDs (with :py:func:`id`) of the property objects in a set
|
|
2342
|
+
property_id_set: Final[FrozenSet[int]]
|
|
2343
|
+
|
|
2344
|
+
def __init__(
|
|
2345
|
+
self,
|
|
2346
|
+
base: "ClassUnion",
|
|
2347
|
+
inheritances: Sequence["Interface"],
|
|
2348
|
+
) -> None:
|
|
2349
|
+
"""Initialize with the given values."""
|
|
2350
|
+
self.base = base
|
|
2351
|
+
|
|
2352
|
+
self.name = base.name
|
|
2353
|
+
self.inheritances = inheritances
|
|
2354
|
+
|
|
2355
|
+
implementers = list(base.concrete_descendants)
|
|
2356
|
+
|
|
2357
|
+
if isinstance(base, ConcreteClass):
|
|
2358
|
+
implementers.append(base)
|
|
2359
|
+
|
|
2360
|
+
self.implementers = implementers
|
|
2361
|
+
|
|
2362
|
+
self.properties = [
|
|
2363
|
+
prop for prop in base.properties if prop.specified_for is base
|
|
2364
|
+
]
|
|
2365
|
+
|
|
2366
|
+
self.signatures = [
|
|
2367
|
+
Signature(
|
|
2368
|
+
name=method.name,
|
|
2369
|
+
arguments=method.arguments,
|
|
2370
|
+
returns=method.returns,
|
|
2371
|
+
description=method.description,
|
|
2372
|
+
contracts=method.contracts,
|
|
2373
|
+
parsed=method.parsed,
|
|
2374
|
+
)
|
|
2375
|
+
for method in base.methods
|
|
2376
|
+
if method.specified_for is base
|
|
2377
|
+
]
|
|
2378
|
+
|
|
2379
|
+
self.description = base.description
|
|
2380
|
+
self.parsed = base.parsed
|
|
2381
|
+
|
|
2382
|
+
self.properties_by_name: Mapping[Identifier, Property] = {
|
|
2383
|
+
prop.name: prop for prop in self.properties
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
self.property_id_set = frozenset(id(prop) for prop in self.properties)
|
|
2387
|
+
|
|
2388
|
+
def __repr__(self) -> str:
|
|
2389
|
+
"""Represent the instance as a string for easier debugging."""
|
|
2390
|
+
return (
|
|
2391
|
+
f"<{_MODULE_NAME}.{self.__class__.__name__} {self.name} at 0x{id(self):x}>"
|
|
2392
|
+
)
|
|
2393
|
+
|
|
2394
|
+
|
|
2395
|
+
T = TypeVar("T")
|
|
2396
|
+
|
|
2397
|
+
|
|
2398
|
+
class MetaModel:
|
|
2399
|
+
"""Collect information about the underlying meta-model."""
|
|
2400
|
+
|
|
2401
|
+
#: Description of the meta-model extracted from the docstring
|
|
2402
|
+
description: Final[Optional[DescriptionOfMetaModel]]
|
|
2403
|
+
|
|
2404
|
+
#: Specify the version of the meta-model
|
|
2405
|
+
version: Final[str]
|
|
2406
|
+
|
|
2407
|
+
#: Specify the XML namespace that is used both for de/serialization and for schema
|
|
2408
|
+
#: definitions
|
|
2409
|
+
xml_namespace: Final[Stripped]
|
|
2410
|
+
|
|
2411
|
+
@require(lambda xml_namespace: not xml_namespace.endswith("/"))
|
|
2412
|
+
@require(lambda xml_namespace: '"' not in xml_namespace)
|
|
2413
|
+
@require(lambda xml_namespace: "'" not in xml_namespace)
|
|
2414
|
+
def __init__(
|
|
2415
|
+
self,
|
|
2416
|
+
version: str,
|
|
2417
|
+
xml_namespace: Stripped,
|
|
2418
|
+
description: Optional[DescriptionOfMetaModel],
|
|
2419
|
+
) -> None:
|
|
2420
|
+
self.version = version
|
|
2421
|
+
self.xml_namespace = xml_namespace
|
|
2422
|
+
self.description = description
|
|
2423
|
+
|
|
2424
|
+
|
|
2425
|
+
ClassUnion = Union[AbstractClass, ConcreteClass]
|
|
2426
|
+
|
|
2427
|
+
|
|
2428
|
+
class SymbolTable:
|
|
2429
|
+
"""Represent all the symbols of the intermediate representation."""
|
|
2430
|
+
|
|
2431
|
+
#: List of all our types that we need for the code generation
|
|
2432
|
+
our_types: Final[Sequence["OurType"]]
|
|
2433
|
+
|
|
2434
|
+
#: List of all our types, topologically sorted by inheritance
|
|
2435
|
+
our_types_topologically_sorted: Final[Sequence["OurType"]]
|
|
2436
|
+
|
|
2437
|
+
#: List all constants defined in the meta-model
|
|
2438
|
+
constants: Final[Sequence["ConstantUnion"]]
|
|
2439
|
+
|
|
2440
|
+
#: Map constants by their name
|
|
2441
|
+
constants_by_name: Final[Mapping[Identifier, "ConstantUnion"]]
|
|
2442
|
+
|
|
2443
|
+
#: List of all functions used in the verification
|
|
2444
|
+
verification_functions: Final[Sequence["VerificationUnion"]]
|
|
2445
|
+
|
|
2446
|
+
#: Map verification functions by their name
|
|
2447
|
+
verification_functions_by_name: Final[Mapping[Identifier, "VerificationUnion"]]
|
|
2448
|
+
|
|
2449
|
+
#: Additional information about the source meta-model
|
|
2450
|
+
meta_model: Final[MetaModel]
|
|
2451
|
+
|
|
2452
|
+
_name_to_our_type: Final[Mapping[Identifier, "OurType"]]
|
|
2453
|
+
|
|
2454
|
+
#: List all the enumerations in the symbol table
|
|
2455
|
+
enumerations: Final[Sequence["Enumeration"]]
|
|
2456
|
+
|
|
2457
|
+
#: List all the constrained primitives in the symbol table
|
|
2458
|
+
constrained_primitives: Final[Sequence["ConstrainedPrimitive"]]
|
|
2459
|
+
|
|
2460
|
+
#: List all the classes (abstract and concrete alike) in the symbol table
|
|
2461
|
+
classes: Final[Sequence["ClassUnion"]]
|
|
2462
|
+
|
|
2463
|
+
#: List all the concrete classes in the symbol table
|
|
2464
|
+
concrete_classes: Final[Sequence["ConcreteClass"]]
|
|
2465
|
+
|
|
2466
|
+
# fmt: off
|
|
2467
|
+
@require(
|
|
2468
|
+
lambda our_types: (
|
|
2469
|
+
names := [our_type.name for our_type in our_types],
|
|
2470
|
+
len(names) == len(set(names)),
|
|
2471
|
+
)[1],
|
|
2472
|
+
"Names of our types unique",
|
|
2473
|
+
)
|
|
2474
|
+
@require(
|
|
2475
|
+
lambda our_types, our_types_topologically_sorted:
|
|
2476
|
+
set(
|
|
2477
|
+
id(our_type)
|
|
2478
|
+
for our_type in our_types
|
|
2479
|
+
if not isinstance(our_type, Enumeration)
|
|
2480
|
+
)
|
|
2481
|
+
== set(id(our_type) for our_type in our_types_topologically_sorted),
|
|
2482
|
+
"Only maybe the order differs between our_types and "
|
|
2483
|
+
"our_types_topologically_sorted"
|
|
2484
|
+
)
|
|
2485
|
+
@require(
|
|
2486
|
+
lambda constants: (
|
|
2487
|
+
names := [constant.name for constant in constants],
|
|
2488
|
+
len(names) == len(set(names)),
|
|
2489
|
+
)[1],
|
|
2490
|
+
"Names of the constants unique",
|
|
2491
|
+
)
|
|
2492
|
+
@ensure(
|
|
2493
|
+
lambda self:
|
|
2494
|
+
all(
|
|
2495
|
+
self.must_find_enumeration(enumeration.name)
|
|
2496
|
+
for enumeration in self.enumerations
|
|
2497
|
+
)
|
|
2498
|
+
)
|
|
2499
|
+
@ensure(
|
|
2500
|
+
lambda self:
|
|
2501
|
+
all(
|
|
2502
|
+
self.must_find_constrained_primitive(constrained_primitive.name)
|
|
2503
|
+
for constrained_primitive in self.constrained_primitives
|
|
2504
|
+
)
|
|
2505
|
+
)
|
|
2506
|
+
@ensure(
|
|
2507
|
+
lambda self:
|
|
2508
|
+
all(
|
|
2509
|
+
self.must_find_concrete_class(cls.name)
|
|
2510
|
+
for cls in self.concrete_classes
|
|
2511
|
+
)
|
|
2512
|
+
)
|
|
2513
|
+
@ensure(
|
|
2514
|
+
lambda self:
|
|
2515
|
+
all(
|
|
2516
|
+
self.must_find_class(cls.name)
|
|
2517
|
+
for cls in self.classes
|
|
2518
|
+
)
|
|
2519
|
+
)
|
|
2520
|
+
@ensure(
|
|
2521
|
+
lambda self:
|
|
2522
|
+
all(
|
|
2523
|
+
self.verification_functions_by_name[func.name] is func
|
|
2524
|
+
for func in self.verification_functions
|
|
2525
|
+
)
|
|
2526
|
+
and len(self.verification_functions_by_name) == len(
|
|
2527
|
+
self.verification_functions),
|
|
2528
|
+
"The verification functions and their mapping by name are consistent"
|
|
2529
|
+
)
|
|
2530
|
+
@ensure(
|
|
2531
|
+
lambda self:
|
|
2532
|
+
all(
|
|
2533
|
+
self.constants_by_name[constant.name] is constant
|
|
2534
|
+
for constant in self.constants
|
|
2535
|
+
) and len(self.constants_by_name) == len(self.constants),
|
|
2536
|
+
"The constants and their mapping by name are consistent"
|
|
2537
|
+
)
|
|
2538
|
+
@ensure(
|
|
2539
|
+
lambda self:
|
|
2540
|
+
all(
|
|
2541
|
+
(
|
|
2542
|
+
found_our_type := self.find_our_type(our_type.name),
|
|
2543
|
+
found_our_type is not None and found_our_type is our_type
|
|
2544
|
+
)[1]
|
|
2545
|
+
for our_type in self.our_types
|
|
2546
|
+
),
|
|
2547
|
+
"Finding our types is consistent with ``our_types``"
|
|
2548
|
+
)
|
|
2549
|
+
# fmt: on
|
|
2550
|
+
def __init__(
|
|
2551
|
+
self,
|
|
2552
|
+
our_types: Sequence["OurType"],
|
|
2553
|
+
our_types_topologically_sorted: Sequence["OurTypeExceptEnumeration"],
|
|
2554
|
+
constants: Sequence["ConstantUnion"],
|
|
2555
|
+
verification_functions: Sequence["VerificationUnion"],
|
|
2556
|
+
meta_model: MetaModel,
|
|
2557
|
+
) -> None:
|
|
2558
|
+
"""Initialize with the given values and map by name."""
|
|
2559
|
+
self.our_types = our_types
|
|
2560
|
+
self.our_types_topologically_sorted = our_types_topologically_sorted
|
|
2561
|
+
self.constants = constants
|
|
2562
|
+
self.verification_functions = verification_functions
|
|
2563
|
+
self.meta_model = meta_model
|
|
2564
|
+
|
|
2565
|
+
self.constants_by_name = {constant.name: constant for constant in constants}
|
|
2566
|
+
|
|
2567
|
+
self.verification_functions_by_name = {
|
|
2568
|
+
func.name: func for func in self.verification_functions
|
|
2569
|
+
}
|
|
2570
|
+
|
|
2571
|
+
self.enumerations = [
|
|
2572
|
+
our_type for our_type in our_types if isinstance(our_type, Enumeration)
|
|
2573
|
+
]
|
|
2574
|
+
|
|
2575
|
+
self.classes = [
|
|
2576
|
+
our_type
|
|
2577
|
+
for our_type in our_types
|
|
2578
|
+
if isinstance(our_type, (AbstractClass, ConcreteClass))
|
|
2579
|
+
]
|
|
2580
|
+
|
|
2581
|
+
self.concrete_classes = [
|
|
2582
|
+
our_type for our_type in our_types if isinstance(our_type, ConcreteClass)
|
|
2583
|
+
]
|
|
2584
|
+
|
|
2585
|
+
self.constrained_primitives = [
|
|
2586
|
+
our_type
|
|
2587
|
+
for our_type in our_types
|
|
2588
|
+
if isinstance(our_type, ConstrainedPrimitive)
|
|
2589
|
+
]
|
|
2590
|
+
|
|
2591
|
+
self._name_to_our_type = {our_type.name: our_type for our_type in our_types}
|
|
2592
|
+
|
|
2593
|
+
def find_our_type(self, name: Identifier) -> Optional["OurType"]:
|
|
2594
|
+
"""Find our type with the given ``name``."""
|
|
2595
|
+
return self._name_to_our_type.get(name, None)
|
|
2596
|
+
|
|
2597
|
+
def must_find_our_type(self, name: Identifier) -> "OurType":
|
|
2598
|
+
"""
|
|
2599
|
+
Find our type with the given ``name``.
|
|
2600
|
+
|
|
2601
|
+
:raise: :py:class:`KeyError` if the ``name`` is not in our types.
|
|
2602
|
+
"""
|
|
2603
|
+
result = self.find_our_type(name)
|
|
2604
|
+
if result is None:
|
|
2605
|
+
raise KeyError(name)
|
|
2606
|
+
|
|
2607
|
+
return result
|
|
2608
|
+
|
|
2609
|
+
def must_find_enumeration(self, name: Identifier) -> "Enumeration":
|
|
2610
|
+
"""
|
|
2611
|
+
Find the enumeration with the given ``name``.
|
|
2612
|
+
|
|
2613
|
+
:raise: :py:class:`KeyError` if the ``name`` is not in our types.
|
|
2614
|
+
:raise:
|
|
2615
|
+
:py:class:`TypeError` if the ``name`` is our type,
|
|
2616
|
+
but is not an enumeration.
|
|
2617
|
+
"""
|
|
2618
|
+
result = self.find_our_type(name)
|
|
2619
|
+
if result is None:
|
|
2620
|
+
raise KeyError(name)
|
|
2621
|
+
|
|
2622
|
+
if not isinstance(result, Enumeration):
|
|
2623
|
+
raise TypeError(
|
|
2624
|
+
f"Found {name} in our types; "
|
|
2625
|
+
f"expected an instance of {Enumeration.__name__}, "
|
|
2626
|
+
f"but got {type(result)}: {result}"
|
|
2627
|
+
)
|
|
2628
|
+
|
|
2629
|
+
return result
|
|
2630
|
+
|
|
2631
|
+
def must_find_constrained_primitive(
|
|
2632
|
+
self, name: Identifier
|
|
2633
|
+
) -> "ConstrainedPrimitive":
|
|
2634
|
+
"""
|
|
2635
|
+
Find the constrained primitive with the given ``name``.
|
|
2636
|
+
|
|
2637
|
+
:raise: :py:class:`KeyError` if the ``name`` is not in our types.
|
|
2638
|
+
:raise:
|
|
2639
|
+
:py:class:`TypeError` if the ``name`` is our type,
|
|
2640
|
+
but is not a constrained primitive.
|
|
2641
|
+
"""
|
|
2642
|
+
result = self.find_our_type(name)
|
|
2643
|
+
if result is None:
|
|
2644
|
+
raise KeyError(name)
|
|
2645
|
+
|
|
2646
|
+
if not isinstance(result, ConstrainedPrimitive):
|
|
2647
|
+
raise TypeError(
|
|
2648
|
+
f"Found {name} in our types; "
|
|
2649
|
+
f"expected an instance of {ConstrainedPrimitive.__name__}, "
|
|
2650
|
+
f"but got {type(result)}: {result}"
|
|
2651
|
+
)
|
|
2652
|
+
|
|
2653
|
+
return result
|
|
2654
|
+
|
|
2655
|
+
def must_find_class(self, name: Identifier) -> "ClassUnion":
|
|
2656
|
+
"""
|
|
2657
|
+
Find the class with the given ``name``.
|
|
2658
|
+
|
|
2659
|
+
:raise: :py:class:`KeyError` if the ``name`` is not in our types.
|
|
2660
|
+
:raise: :py:class:`TypeError` if the ``name`` is our type, but is not a class.
|
|
2661
|
+
"""
|
|
2662
|
+
result = self.find_our_type(name)
|
|
2663
|
+
if result is None:
|
|
2664
|
+
raise KeyError(name)
|
|
2665
|
+
|
|
2666
|
+
if not isinstance(result, (AbstractClass, ConcreteClass)):
|
|
2667
|
+
raise TypeError(
|
|
2668
|
+
f"Found {name} in our types; "
|
|
2669
|
+
f"expected an instance of {ClassUnion}, "
|
|
2670
|
+
f"but got {type(result)}: {result}"
|
|
2671
|
+
)
|
|
2672
|
+
|
|
2673
|
+
return result
|
|
2674
|
+
|
|
2675
|
+
def must_find_abstract_class(self, name: Identifier) -> "AbstractClass":
|
|
2676
|
+
"""
|
|
2677
|
+
Find the abstract class with the given ``name``.
|
|
2678
|
+
|
|
2679
|
+
:raise: :py:class:`KeyError` if the ``name`` is not in our types.
|
|
2680
|
+
:raise:
|
|
2681
|
+
:py:class:`TypeError` if the ``name`` is our type,
|
|
2682
|
+
but is not an abstract class.
|
|
2683
|
+
"""
|
|
2684
|
+
result = self.find_our_type(name)
|
|
2685
|
+
if result is None:
|
|
2686
|
+
raise KeyError(name)
|
|
2687
|
+
|
|
2688
|
+
if not isinstance(result, AbstractClass):
|
|
2689
|
+
raise TypeError(
|
|
2690
|
+
f"Found {name} in our types; "
|
|
2691
|
+
f"expected an instance of {AbstractClass.__name__}, "
|
|
2692
|
+
f"but got {type(result)}: {result}"
|
|
2693
|
+
)
|
|
2694
|
+
|
|
2695
|
+
return result
|
|
2696
|
+
|
|
2697
|
+
def must_find_concrete_class(self, name: Identifier) -> "ConcreteClass":
|
|
2698
|
+
"""
|
|
2699
|
+
Find the concrete class with the given ``name``.
|
|
2700
|
+
|
|
2701
|
+
:raise: :py:class:`KeyError` if the ``name`` is not in our types.
|
|
2702
|
+
:raise:
|
|
2703
|
+
:py:class:`TypeError` if the ``name`` is our type,
|
|
2704
|
+
but is not a concrete class.
|
|
2705
|
+
"""
|
|
2706
|
+
result = self.find_our_type(name)
|
|
2707
|
+
if result is None:
|
|
2708
|
+
raise KeyError(name)
|
|
2709
|
+
|
|
2710
|
+
if not isinstance(result, ConcreteClass):
|
|
2711
|
+
raise TypeError(
|
|
2712
|
+
f"Found {name} in our types; "
|
|
2713
|
+
f"expected an instance of {ConcreteClass.__name__}, "
|
|
2714
|
+
f"but got {type(result)}: {result}"
|
|
2715
|
+
)
|
|
2716
|
+
|
|
2717
|
+
return result
|
|
2718
|
+
|
|
2719
|
+
def must_find_class_or_constrained_primitive(
|
|
2720
|
+
self, name: Identifier
|
|
2721
|
+
) -> Union["ClassUnion", ConstrainedPrimitive]:
|
|
2722
|
+
"""
|
|
2723
|
+
Find the class with the given ``name``.
|
|
2724
|
+
|
|
2725
|
+
:raise: :py:class:`KeyError` if the ``name`` is not in our types.
|
|
2726
|
+
:raise:
|
|
2727
|
+
:py:class:`TypeError` if the ``name`` is our type, but is neither a class
|
|
2728
|
+
nor a constrained primitive
|
|
2729
|
+
"""
|
|
2730
|
+
result = self.find_our_type(name)
|
|
2731
|
+
if result is None:
|
|
2732
|
+
raise KeyError(name)
|
|
2733
|
+
|
|
2734
|
+
if not isinstance(result, (AbstractClass, ConcreteClass, ConstrainedPrimitive)):
|
|
2735
|
+
raise TypeError(
|
|
2736
|
+
f"Found {name} in our types; "
|
|
2737
|
+
f"expected an instance of either {AbstractClass.__name__}, "
|
|
2738
|
+
f"{ConcreteClass.__name__} or {ConstrainedPrimitive.__name__},"
|
|
2739
|
+
f"but got {type(result)}: {result}"
|
|
2740
|
+
)
|
|
2741
|
+
|
|
2742
|
+
return result
|
|
2743
|
+
|
|
2744
|
+
|
|
2745
|
+
def try_primitive_type(type_annotation: TypeAnnotationUnion) -> Optional[PrimitiveType]:
|
|
2746
|
+
"""
|
|
2747
|
+
Try to get the underlying primitive type of the type annotation.
|
|
2748
|
+
|
|
2749
|
+
If it is neither a primitive type annotation nor a constrained primitive,
|
|
2750
|
+
return None.
|
|
2751
|
+
"""
|
|
2752
|
+
if isinstance(type_annotation, PrimitiveTypeAnnotation):
|
|
2753
|
+
return type_annotation.a_type
|
|
2754
|
+
|
|
2755
|
+
elif isinstance(type_annotation, OurTypeAnnotation) and isinstance(
|
|
2756
|
+
type_annotation.our_type, ConstrainedPrimitive
|
|
2757
|
+
):
|
|
2758
|
+
return type_annotation.our_type.constrainee
|
|
2759
|
+
else:
|
|
2760
|
+
return None
|
|
2761
|
+
|
|
2762
|
+
|
|
2763
|
+
def map_descendability(
|
|
2764
|
+
type_annotation: TypeAnnotationUnion,
|
|
2765
|
+
) -> MutableMapping[TypeAnnotationUnion, bool]:
|
|
2766
|
+
"""
|
|
2767
|
+
Map the type annotation recursively by the descendability.
|
|
2768
|
+
|
|
2769
|
+
The descendability means that the type annotation references an interface
|
|
2770
|
+
or a class *or* that it is a subscripted type annotation which subscribes one or
|
|
2771
|
+
more classes of the meta-model.
|
|
2772
|
+
|
|
2773
|
+
Constrained primitives are considered primitives and thus non-descendable.
|
|
2774
|
+
|
|
2775
|
+
The mapping is a form of caching. Otherwise, the time complexity would be quadratic
|
|
2776
|
+
if we queried at each type annotation subscript.
|
|
2777
|
+
"""
|
|
2778
|
+
mapping = dict() # type: MutableMapping[TypeAnnotationUnion, bool]
|
|
2779
|
+
|
|
2780
|
+
def recurse(a_type_annotation: TypeAnnotationUnion) -> bool:
|
|
2781
|
+
"""Recursively iterate over subscripted type annotations."""
|
|
2782
|
+
if isinstance(a_type_annotation, PrimitiveTypeAnnotation):
|
|
2783
|
+
mapping[a_type_annotation] = False
|
|
2784
|
+
return False
|
|
2785
|
+
|
|
2786
|
+
elif isinstance(a_type_annotation, OurTypeAnnotation):
|
|
2787
|
+
result: bool
|
|
2788
|
+
if isinstance(a_type_annotation.our_type, Enumeration):
|
|
2789
|
+
result = False
|
|
2790
|
+
elif isinstance(a_type_annotation.our_type, ConstrainedPrimitive):
|
|
2791
|
+
result = False
|
|
2792
|
+
elif isinstance(a_type_annotation.our_type, Class):
|
|
2793
|
+
result = True
|
|
2794
|
+
else:
|
|
2795
|
+
assert_never(a_type_annotation.our_type)
|
|
2796
|
+
|
|
2797
|
+
mapping[a_type_annotation] = result
|
|
2798
|
+
return result
|
|
2799
|
+
|
|
2800
|
+
elif isinstance(a_type_annotation, ListTypeAnnotation):
|
|
2801
|
+
result = recurse(a_type_annotation=a_type_annotation.items)
|
|
2802
|
+
mapping[a_type_annotation] = result
|
|
2803
|
+
return result
|
|
2804
|
+
|
|
2805
|
+
elif isinstance(a_type_annotation, OptionalTypeAnnotation):
|
|
2806
|
+
result = recurse(a_type_annotation=a_type_annotation.value)
|
|
2807
|
+
mapping[a_type_annotation] = result
|
|
2808
|
+
return result
|
|
2809
|
+
|
|
2810
|
+
else:
|
|
2811
|
+
assert_never(a_type_annotation)
|
|
2812
|
+
|
|
2813
|
+
raise AssertionError("Should not have gotten here")
|
|
2814
|
+
|
|
2815
|
+
_ = recurse(a_type_annotation=type_annotation)
|
|
2816
|
+
|
|
2817
|
+
return mapping
|
|
2818
|
+
|
|
2819
|
+
|
|
2820
|
+
class _ConstructorArgumentOfClass:
|
|
2821
|
+
"""Represent a constructor argument with its corresponding class."""
|
|
2822
|
+
|
|
2823
|
+
def __init__(self, arg: Argument, cls: Class) -> None:
|
|
2824
|
+
"""Initialize with the given values."""
|
|
2825
|
+
self.arg = arg
|
|
2826
|
+
self.cls = cls
|
|
2827
|
+
|
|
2828
|
+
|
|
2829
|
+
def collect_ids_of_our_types_in_properties(symbol_table: SymbolTable) -> Set[int]:
|
|
2830
|
+
"""
|
|
2831
|
+
Collect the IDs of our types occurring in type annotations of the properties.
|
|
2832
|
+
|
|
2833
|
+
The IDs refer to IDs of the Python objects in this context.
|
|
2834
|
+
"""
|
|
2835
|
+
result = set() # type: Set[int]
|
|
2836
|
+
for cls in symbol_table.classes:
|
|
2837
|
+
for prop in cls.properties:
|
|
2838
|
+
type_anno = prop.type_annotation
|
|
2839
|
+
|
|
2840
|
+
old_type_anno = None # type: Optional[TypeAnnotation]
|
|
2841
|
+
while True:
|
|
2842
|
+
if isinstance(type_anno, OptionalTypeAnnotation):
|
|
2843
|
+
# noinspection PyUnresolvedReferences
|
|
2844
|
+
type_anno = type_anno.value
|
|
2845
|
+
elif isinstance(type_anno, ListTypeAnnotation):
|
|
2846
|
+
type_anno = type_anno.items
|
|
2847
|
+
elif isinstance(type_anno, PrimitiveTypeAnnotation):
|
|
2848
|
+
break
|
|
2849
|
+
elif isinstance(type_anno, OurTypeAnnotation):
|
|
2850
|
+
result.add(id(type_anno.our_type))
|
|
2851
|
+
break
|
|
2852
|
+
else:
|
|
2853
|
+
assert_never(type_anno)
|
|
2854
|
+
|
|
2855
|
+
assert old_type_anno is not type_anno, "Loop invariant"
|
|
2856
|
+
old_type_anno = type_anno
|
|
2857
|
+
|
|
2858
|
+
return result
|
|
2859
|
+
|
|
2860
|
+
|
|
2861
|
+
DescriptionUnion = Union[
|
|
2862
|
+
DescriptionOfMetaModel,
|
|
2863
|
+
DescriptionOfOurType,
|
|
2864
|
+
DescriptionOfProperty,
|
|
2865
|
+
DescriptionOfEnumerationLiteral,
|
|
2866
|
+
DescriptionOfSignature,
|
|
2867
|
+
DescriptionOfConstant,
|
|
2868
|
+
]
|
|
2869
|
+
assert_union_of_descendants_exhaustive(
|
|
2870
|
+
union=DescriptionUnion, base_class=SummaryRemarksDescription
|
|
2871
|
+
)
|
|
2872
|
+
assert_union_of_descendants_exhaustive(union=ClassUnion, base_class=Class)
|
|
2873
|
+
|
|
2874
|
+
ClassUnionAsTuple = (AbstractClass, ConcreteClass)
|
|
2875
|
+
assert ClassUnionAsTuple == get_args(ClassUnion)
|
|
2876
|
+
|
|
2877
|
+
MethodUnion = Union[UnderstoodMethod, ImplementationSpecificMethod]
|
|
2878
|
+
assert_union_of_descendants_exhaustive(union=MethodUnion, base_class=Method)
|
|
2879
|
+
|
|
2880
|
+
OurType = Union[Enumeration, ConstrainedPrimitive, ClassUnion]
|
|
2881
|
+
|
|
2882
|
+
OurTypeExceptEnumeration = Union[ConstrainedPrimitive, ClassUnion]
|
|
2883
|
+
assert_union_without_excluded(
|
|
2884
|
+
original_union=OurType,
|
|
2885
|
+
subset_union=OurTypeExceptEnumeration,
|
|
2886
|
+
excluded=[Enumeration],
|
|
2887
|
+
)
|
|
2888
|
+
|
|
2889
|
+
ConstantSetUnion = Union[ConstantSetOfPrimitives, ConstantSetOfEnumerationLiterals]
|
|
2890
|
+
|
|
2891
|
+
ConstantUnion = Union[
|
|
2892
|
+
ConstantPrimitive, ConstantSetOfPrimitives, ConstantSetOfEnumerationLiterals
|
|
2893
|
+
]
|
|
2894
|
+
assert_union_of_descendants_exhaustive(union=ConstantUnion, base_class=Constant)
|
|
2895
|
+
|
|
2896
|
+
VerificationUnion = Union[
|
|
2897
|
+
ImplementationSpecificVerification,
|
|
2898
|
+
PatternVerification,
|
|
2899
|
+
TranspilableVerification,
|
|
2900
|
+
]
|
|
2901
|
+
assert_union_of_descendants_exhaustive(union=VerificationUnion, base_class=Verification)
|