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,1471 @@
|
|
|
1
|
+
"""Generate the invariant verifiers from the intermediate representation."""
|
|
2
|
+
import io
|
|
3
|
+
import textwrap
|
|
4
|
+
from typing import (
|
|
5
|
+
Tuple,
|
|
6
|
+
Optional,
|
|
7
|
+
List,
|
|
8
|
+
Sequence,
|
|
9
|
+
Mapping,
|
|
10
|
+
Union,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
from icontract import ensure, require
|
|
14
|
+
|
|
15
|
+
from aas_core_codegen import intermediate, specific_implementations
|
|
16
|
+
from aas_core_codegen.common import (
|
|
17
|
+
Error,
|
|
18
|
+
Stripped,
|
|
19
|
+
assert_never,
|
|
20
|
+
Identifier,
|
|
21
|
+
indent_but_first_line,
|
|
22
|
+
wrap_text_into_lines,
|
|
23
|
+
assert_union_without_excluded,
|
|
24
|
+
)
|
|
25
|
+
from aas_core_codegen.python.common import (
|
|
26
|
+
INDENT as I,
|
|
27
|
+
INDENT2 as II,
|
|
28
|
+
INDENT3 as III,
|
|
29
|
+
INDENT4 as IIII,
|
|
30
|
+
)
|
|
31
|
+
from aas_core_codegen.intermediate import type_inference as intermediate_type_inference
|
|
32
|
+
from aas_core_codegen.parse import tree as parse_tree, retree as parse_retree
|
|
33
|
+
from aas_core_codegen.python import (
|
|
34
|
+
common as python_common,
|
|
35
|
+
naming as python_naming,
|
|
36
|
+
description as python_description,
|
|
37
|
+
transpilation as python_transpilation,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# region Verify
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def verify(
|
|
45
|
+
spec_impls: specific_implementations.SpecificImplementations,
|
|
46
|
+
verification_functions: Sequence[intermediate.Verification],
|
|
47
|
+
) -> Optional[List[str]]:
|
|
48
|
+
"""Verify all the implementation snippets related to verification."""
|
|
49
|
+
errors = [] # type: List[str]
|
|
50
|
+
|
|
51
|
+
expected_keys = [] # type: List[specific_implementations.ImplementationKey]
|
|
52
|
+
|
|
53
|
+
for func in verification_functions:
|
|
54
|
+
if isinstance(func, intermediate.ImplementationSpecificVerification):
|
|
55
|
+
expected_keys.append(
|
|
56
|
+
specific_implementations.ImplementationKey(
|
|
57
|
+
f"Verification/{func.name}.py"
|
|
58
|
+
),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
for key in expected_keys:
|
|
62
|
+
if key not in spec_impls:
|
|
63
|
+
errors.append(f"The implementation snippet is missing for: {key}")
|
|
64
|
+
|
|
65
|
+
if len(errors) == 0:
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
return errors
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# endregion
|
|
72
|
+
|
|
73
|
+
# region Generate
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class _PatternVerificationTranspiler(
|
|
77
|
+
parse_tree.RestrictedTransformer[Tuple[Optional[Stripped], Optional[Error]]]
|
|
78
|
+
):
|
|
79
|
+
"""Transpile a statement of a pattern verification into Python."""
|
|
80
|
+
|
|
81
|
+
@ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
|
|
82
|
+
def _transform_joined_str_values(
|
|
83
|
+
self, values: Sequence[Union[str, parse_tree.FormattedValue]]
|
|
84
|
+
) -> Tuple[Optional[Stripped], Optional[Error]]:
|
|
85
|
+
"""Transform the values of a joined string to a Python string literal."""
|
|
86
|
+
# If we do not need interpolation, simply return the string literals
|
|
87
|
+
# joined together by newlines.
|
|
88
|
+
needs_interpolation = any(
|
|
89
|
+
isinstance(value, parse_tree.FormattedValue) for value in values
|
|
90
|
+
)
|
|
91
|
+
if not needs_interpolation:
|
|
92
|
+
return (
|
|
93
|
+
Stripped(
|
|
94
|
+
python_common.string_literal(
|
|
95
|
+
"".join(value for value in values) # type: ignore
|
|
96
|
+
)
|
|
97
|
+
),
|
|
98
|
+
None,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
parts = [] # type: List[str]
|
|
102
|
+
|
|
103
|
+
# NOTE (mristin, 2022-09-30):
|
|
104
|
+
# See which quotes occur more often in the non-interpolated parts, so that we
|
|
105
|
+
# pick the escaping scheme which will result in as little escapes as possible.
|
|
106
|
+
double_quotes_count = 0
|
|
107
|
+
single_quotes_count = 0
|
|
108
|
+
|
|
109
|
+
for value in values:
|
|
110
|
+
if isinstance(value, str):
|
|
111
|
+
double_quotes_count += value.count('"')
|
|
112
|
+
single_quotes_count += value.count("'")
|
|
113
|
+
|
|
114
|
+
elif isinstance(value, parse_tree.FormattedValue):
|
|
115
|
+
pass
|
|
116
|
+
else:
|
|
117
|
+
assert_never(value)
|
|
118
|
+
|
|
119
|
+
# Pick the escaping scheme
|
|
120
|
+
if single_quotes_count <= double_quotes_count:
|
|
121
|
+
enclosing = "'"
|
|
122
|
+
quoting = python_common.StringQuoting.SINGLE_QUOTES
|
|
123
|
+
else:
|
|
124
|
+
enclosing = '"'
|
|
125
|
+
quoting = python_common.StringQuoting.DOUBLE_QUOTES
|
|
126
|
+
|
|
127
|
+
for value in values:
|
|
128
|
+
if isinstance(value, str):
|
|
129
|
+
parts.append(
|
|
130
|
+
python_common.string_literal(
|
|
131
|
+
value,
|
|
132
|
+
quoting=quoting,
|
|
133
|
+
without_enclosing=True,
|
|
134
|
+
duplicate_curly_brackets=True,
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
elif isinstance(value, parse_tree.FormattedValue):
|
|
139
|
+
code, error = self.transform(value.value)
|
|
140
|
+
if error is not None:
|
|
141
|
+
return None, error
|
|
142
|
+
|
|
143
|
+
assert code is not None
|
|
144
|
+
|
|
145
|
+
assert (
|
|
146
|
+
"\n" not in code
|
|
147
|
+
), f"New-lines are not expected in formatted values, but got: {code}"
|
|
148
|
+
|
|
149
|
+
parts.append(f"{{{code}}}")
|
|
150
|
+
else:
|
|
151
|
+
assert_never(value)
|
|
152
|
+
|
|
153
|
+
writer = io.StringIO()
|
|
154
|
+
writer.write("f")
|
|
155
|
+
writer.write(enclosing)
|
|
156
|
+
for part in parts:
|
|
157
|
+
writer.write(part)
|
|
158
|
+
writer.write(enclosing)
|
|
159
|
+
|
|
160
|
+
return Stripped(writer.getvalue()), None
|
|
161
|
+
|
|
162
|
+
@ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
|
|
163
|
+
def transform_constant(
|
|
164
|
+
self, node: parse_tree.Constant
|
|
165
|
+
) -> Tuple[Optional[Stripped], Optional[Error]]:
|
|
166
|
+
if isinstance(node.value, str):
|
|
167
|
+
# NOTE (mristin, 2022-06-11):
|
|
168
|
+
# We assume that all the string constants are valid regular expressions.
|
|
169
|
+
|
|
170
|
+
regex, parse_error = parse_retree.parse(values=[node.value])
|
|
171
|
+
if parse_error is not None:
|
|
172
|
+
regex_line, pointer_line = parse_retree.render_pointer(
|
|
173
|
+
parse_error.cursor
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
None,
|
|
178
|
+
Error(
|
|
179
|
+
node.original_node,
|
|
180
|
+
f"The string constant could not be parsed "
|
|
181
|
+
f"as a regular expression: \n"
|
|
182
|
+
f"{parse_error.message}\n"
|
|
183
|
+
f"{regex_line}\n"
|
|
184
|
+
f"{pointer_line}",
|
|
185
|
+
),
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
assert regex is not None
|
|
189
|
+
|
|
190
|
+
# NOTE (mristin, 2022-09-30):
|
|
191
|
+
# Strictly speaking, this is a joined string with a single value, a string
|
|
192
|
+
# literal.
|
|
193
|
+
return self._transform_joined_str_values(
|
|
194
|
+
values=parse_retree.render(regex=regex)
|
|
195
|
+
)
|
|
196
|
+
else:
|
|
197
|
+
raise AssertionError(f"Unexpected {node=}")
|
|
198
|
+
|
|
199
|
+
@ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
|
|
200
|
+
def transform_name(
|
|
201
|
+
self, node: parse_tree.Name
|
|
202
|
+
) -> Tuple[Optional[Stripped], Optional[Error]]:
|
|
203
|
+
return Stripped(python_naming.variable_name(node.identifier)), None
|
|
204
|
+
|
|
205
|
+
@ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
|
|
206
|
+
def transform_joined_str(
|
|
207
|
+
self, node: parse_tree.JoinedStr
|
|
208
|
+
) -> Tuple[Optional[Stripped], Optional[Error]]:
|
|
209
|
+
regex, parse_error = parse_retree.parse(values=node.values)
|
|
210
|
+
if parse_error is not None:
|
|
211
|
+
regex_line, pointer_line = parse_retree.render_pointer(parse_error.cursor)
|
|
212
|
+
|
|
213
|
+
return (
|
|
214
|
+
None,
|
|
215
|
+
Error(
|
|
216
|
+
node.original_node,
|
|
217
|
+
f"The joined string could not be parsed "
|
|
218
|
+
f"as a regular expression: \n"
|
|
219
|
+
f"{parse_error.message}\n"
|
|
220
|
+
f"{regex_line}\n"
|
|
221
|
+
f"{pointer_line}",
|
|
222
|
+
),
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
assert regex is not None
|
|
226
|
+
|
|
227
|
+
return self._transform_joined_str_values(
|
|
228
|
+
values=parse_retree.render(regex=regex)
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
def transform_assignment(
|
|
232
|
+
self, node: parse_tree.Assignment
|
|
233
|
+
) -> Tuple[Optional[Stripped], Optional[Error]]:
|
|
234
|
+
assert isinstance(node.target, parse_tree.Name)
|
|
235
|
+
variable = python_naming.variable_name(node.target.identifier)
|
|
236
|
+
code, error = self.transform(node.value)
|
|
237
|
+
if error is not None:
|
|
238
|
+
return None, error
|
|
239
|
+
assert code is not None
|
|
240
|
+
|
|
241
|
+
return Stripped(f"{variable} = {code}"), None
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
@ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
|
|
245
|
+
def _transpile_pattern_verification(
|
|
246
|
+
verification: intermediate.PatternVerification,
|
|
247
|
+
aas_module: python_common.QualifiedModuleName,
|
|
248
|
+
) -> Tuple[Optional[Stripped], Optional[Error]]:
|
|
249
|
+
"""Generate the verification function that checks the regular expressions."""
|
|
250
|
+
# NOTE (mristin, 2022-09-30):
|
|
251
|
+
# We assume that we performed all the checks at the intermediate stage.
|
|
252
|
+
|
|
253
|
+
construct_name = python_naming.function_name(
|
|
254
|
+
Identifier(f"_construct_{verification.name}")
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
blocks = [] # type: List[Stripped]
|
|
258
|
+
|
|
259
|
+
# region Construct block
|
|
260
|
+
|
|
261
|
+
writer = io.StringIO()
|
|
262
|
+
writer.write(
|
|
263
|
+
f"""\
|
|
264
|
+
# noinspection SpellCheckingInspection
|
|
265
|
+
def {construct_name}() -> Pattern[str]:
|
|
266
|
+
"""
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
transpiler = _PatternVerificationTranspiler()
|
|
270
|
+
|
|
271
|
+
for i, stmt in enumerate(verification.parsed.body):
|
|
272
|
+
if i == len(verification.parsed.body) - 1:
|
|
273
|
+
break
|
|
274
|
+
|
|
275
|
+
code, error = transpiler.transform(stmt)
|
|
276
|
+
if error is not None:
|
|
277
|
+
return None, error
|
|
278
|
+
assert code is not None
|
|
279
|
+
|
|
280
|
+
writer.write(textwrap.indent(code, I))
|
|
281
|
+
writer.write("\n")
|
|
282
|
+
|
|
283
|
+
if len(verification.parsed.body) >= 2:
|
|
284
|
+
writer.write("\n")
|
|
285
|
+
|
|
286
|
+
pattern_expr, error = transpiler.transform(verification.pattern_expr)
|
|
287
|
+
if error is not None:
|
|
288
|
+
return None, error
|
|
289
|
+
assert pattern_expr is not None
|
|
290
|
+
|
|
291
|
+
# A pragmatic heuristics for breaking lines
|
|
292
|
+
if len(pattern_expr) < 50:
|
|
293
|
+
writer.write(textwrap.indent(f"return re.compile({pattern_expr})", I))
|
|
294
|
+
else:
|
|
295
|
+
writer.write(
|
|
296
|
+
textwrap.indent(
|
|
297
|
+
f"""\
|
|
298
|
+
return re.compile(
|
|
299
|
+
{I}{indent_but_first_line(pattern_expr, I)}
|
|
300
|
+
)""",
|
|
301
|
+
I,
|
|
302
|
+
)
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
blocks.append(Stripped(writer.getvalue()))
|
|
306
|
+
|
|
307
|
+
# endregion
|
|
308
|
+
|
|
309
|
+
# region Initialize the regex
|
|
310
|
+
|
|
311
|
+
regex_name = python_naming.constant_name(Identifier(f"_regex_{verification.name}"))
|
|
312
|
+
|
|
313
|
+
blocks.append(Stripped(f"{regex_name} = {construct_name}()"))
|
|
314
|
+
|
|
315
|
+
assert len(verification.arguments) == 1
|
|
316
|
+
assert isinstance(
|
|
317
|
+
verification.arguments[0].type_annotation, intermediate.PrimitiveTypeAnnotation
|
|
318
|
+
)
|
|
319
|
+
# noinspection PyUnresolvedReferences
|
|
320
|
+
assert (
|
|
321
|
+
verification.arguments[0].type_annotation.a_type
|
|
322
|
+
== intermediate.PrimitiveType.STR
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
arg_name = python_naming.argument_name(verification.arguments[0].name)
|
|
326
|
+
|
|
327
|
+
function_name = python_naming.function_name(verification.name)
|
|
328
|
+
|
|
329
|
+
writer = io.StringIO()
|
|
330
|
+
writer.write(
|
|
331
|
+
f"""\
|
|
332
|
+
def {function_name}({arg_name}: str) -> bool:
|
|
333
|
+
"""
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
if verification.description is not None:
|
|
337
|
+
(
|
|
338
|
+
docstring,
|
|
339
|
+
docstring_errors,
|
|
340
|
+
) = python_description.generate_docstring_for_signature(
|
|
341
|
+
description=verification.description,
|
|
342
|
+
context=python_description.Context(
|
|
343
|
+
aas_module=aas_module,
|
|
344
|
+
module=Identifier("verification"),
|
|
345
|
+
cls_or_enum=None,
|
|
346
|
+
),
|
|
347
|
+
)
|
|
348
|
+
if docstring_errors is not None:
|
|
349
|
+
return None, Error(
|
|
350
|
+
verification.description.parsed.node,
|
|
351
|
+
"Failed to generate the docstring",
|
|
352
|
+
docstring_errors,
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
assert docstring is not None
|
|
356
|
+
|
|
357
|
+
writer.write(textwrap.indent(docstring, I))
|
|
358
|
+
writer.write("\n")
|
|
359
|
+
|
|
360
|
+
writer.write(f"{I}return {regex_name}.match({arg_name}) is not None")
|
|
361
|
+
|
|
362
|
+
blocks.append(Stripped(writer.getvalue()))
|
|
363
|
+
|
|
364
|
+
# endregion
|
|
365
|
+
|
|
366
|
+
writer = io.StringIO()
|
|
367
|
+
for i, block in enumerate(blocks):
|
|
368
|
+
if i > 0:
|
|
369
|
+
writer.write("\n\n\n")
|
|
370
|
+
|
|
371
|
+
writer.write(block)
|
|
372
|
+
|
|
373
|
+
return Stripped(writer.getvalue()), None
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
class _TranspilableVerificationTranspiler(python_transpilation.Transpiler):
|
|
377
|
+
"""Transpile the body of a :class:`.TranspilableVerification`."""
|
|
378
|
+
|
|
379
|
+
# fmt: off
|
|
380
|
+
@require(
|
|
381
|
+
lambda environment, verification:
|
|
382
|
+
all(
|
|
383
|
+
environment.find(arg.name) is not None
|
|
384
|
+
for arg in verification.arguments
|
|
385
|
+
),
|
|
386
|
+
"All arguments defined in the environment"
|
|
387
|
+
)
|
|
388
|
+
# fmt: on
|
|
389
|
+
def __init__(
|
|
390
|
+
self,
|
|
391
|
+
type_map: Mapping[
|
|
392
|
+
parse_tree.Node, intermediate_type_inference.TypeAnnotationUnion
|
|
393
|
+
],
|
|
394
|
+
environment: intermediate_type_inference.Environment,
|
|
395
|
+
symbol_table: intermediate.SymbolTable,
|
|
396
|
+
verification: intermediate.TranspilableVerification,
|
|
397
|
+
) -> None:
|
|
398
|
+
"""Initialize with the given values."""
|
|
399
|
+
python_transpilation.Transpiler.__init__(
|
|
400
|
+
self, type_map=type_map, environment=environment
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
self._symbol_table = symbol_table
|
|
404
|
+
|
|
405
|
+
self._argument_name_set = frozenset(arg.name for arg in verification.arguments)
|
|
406
|
+
|
|
407
|
+
def transform_name(
|
|
408
|
+
self, node: parse_tree.Name
|
|
409
|
+
) -> Tuple[Optional[Stripped], Optional[Error]]:
|
|
410
|
+
if node.identifier in self._variable_name_set:
|
|
411
|
+
return Stripped(python_naming.variable_name(node.identifier)), None
|
|
412
|
+
|
|
413
|
+
if node.identifier in self._argument_name_set:
|
|
414
|
+
return Stripped(python_naming.argument_name(node.identifier)), None
|
|
415
|
+
|
|
416
|
+
if node.identifier in self._symbol_table.constants_by_name:
|
|
417
|
+
constant_name = python_naming.constant_name(node.identifier)
|
|
418
|
+
return Stripped(f"aas_constants.{constant_name}"), None
|
|
419
|
+
|
|
420
|
+
if node.identifier in self._symbol_table.verification_functions_by_name:
|
|
421
|
+
return Stripped(python_naming.function_name(node.identifier)), None
|
|
422
|
+
|
|
423
|
+
our_type = self._symbol_table.find_our_type(name=node.identifier)
|
|
424
|
+
if isinstance(our_type, intermediate.Enumeration):
|
|
425
|
+
return (
|
|
426
|
+
Stripped(f"aas_types.{python_naming.enum_name(node.identifier)}"),
|
|
427
|
+
None,
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
return None, Error(
|
|
431
|
+
node.original_node,
|
|
432
|
+
f"We can not determine how to transpile the name {node.identifier!r} "
|
|
433
|
+
f"to Python. We could not find it neither in the constants, nor in "
|
|
434
|
+
f"verification functions, nor as an enumeration. "
|
|
435
|
+
f"If you expect this name to be transpilable, please contact "
|
|
436
|
+
f"the developers.",
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def _transpile_transpilable_verification(
|
|
441
|
+
verification: intermediate.TranspilableVerification,
|
|
442
|
+
symbol_table: intermediate.SymbolTable,
|
|
443
|
+
environment: intermediate_type_inference.Environment,
|
|
444
|
+
aas_module: python_common.QualifiedModuleName,
|
|
445
|
+
) -> Tuple[Optional[Stripped], Optional[Error]]:
|
|
446
|
+
"""Transpile a verification function."""
|
|
447
|
+
# fmt: off
|
|
448
|
+
type_inference, error = (
|
|
449
|
+
intermediate_type_inference.infer_for_verification(
|
|
450
|
+
verification=verification,
|
|
451
|
+
base_environment=environment
|
|
452
|
+
)
|
|
453
|
+
)
|
|
454
|
+
# fmt: on
|
|
455
|
+
|
|
456
|
+
if error is not None:
|
|
457
|
+
return None, error
|
|
458
|
+
|
|
459
|
+
assert type_inference is not None
|
|
460
|
+
|
|
461
|
+
transpiler = _TranspilableVerificationTranspiler(
|
|
462
|
+
type_map=type_inference.type_map,
|
|
463
|
+
environment=type_inference.environment_with_args,
|
|
464
|
+
symbol_table=symbol_table,
|
|
465
|
+
verification=verification,
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
body = [] # type: List[Stripped]
|
|
469
|
+
for node in verification.parsed.body:
|
|
470
|
+
stmt, error = transpiler.transform(node)
|
|
471
|
+
if error is not None:
|
|
472
|
+
return None, Error(
|
|
473
|
+
verification.parsed.node,
|
|
474
|
+
f"Failed to transpile the verification function {verification.name!r}",
|
|
475
|
+
[error],
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
assert stmt is not None
|
|
479
|
+
body.append(stmt)
|
|
480
|
+
|
|
481
|
+
writer = io.StringIO()
|
|
482
|
+
|
|
483
|
+
function_name = python_naming.function_name(verification.name)
|
|
484
|
+
|
|
485
|
+
if verification.returns is None:
|
|
486
|
+
return_type = "None"
|
|
487
|
+
else:
|
|
488
|
+
return_type = python_common.generate_type(
|
|
489
|
+
type_annotation=verification.returns, types_module=Identifier("aas_types")
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
arg_defs = [] # type: List[Stripped]
|
|
493
|
+
for arg in verification.arguments:
|
|
494
|
+
arg_type = python_common.generate_type(
|
|
495
|
+
arg.type_annotation, types_module=Identifier("aas_types")
|
|
496
|
+
)
|
|
497
|
+
arg_name = python_naming.argument_name(arg.name)
|
|
498
|
+
arg_defs.append(Stripped(f"{arg_name}: {arg_type}"))
|
|
499
|
+
|
|
500
|
+
if len(arg_defs) == 0:
|
|
501
|
+
writer.write(
|
|
502
|
+
f"""\
|
|
503
|
+
def {function_name}() -> {return_type}:"""
|
|
504
|
+
)
|
|
505
|
+
else:
|
|
506
|
+
writer.write(
|
|
507
|
+
f"""\
|
|
508
|
+
def {function_name}(
|
|
509
|
+
"""
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
for i, arg_def in enumerate(arg_defs):
|
|
513
|
+
if i > 0:
|
|
514
|
+
writer.write(",\n")
|
|
515
|
+
writer.write(textwrap.indent(arg_def, I))
|
|
516
|
+
|
|
517
|
+
writer.write("\n")
|
|
518
|
+
writer.write(
|
|
519
|
+
f"""\
|
|
520
|
+
) -> {return_type}:"""
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
docstring = None # type: Optional[Stripped]
|
|
524
|
+
if verification.description is not None:
|
|
525
|
+
(
|
|
526
|
+
docstring,
|
|
527
|
+
docstring_errors,
|
|
528
|
+
) = python_description.generate_docstring_for_signature(
|
|
529
|
+
description=verification.description,
|
|
530
|
+
context=python_description.Context(
|
|
531
|
+
aas_module=aas_module,
|
|
532
|
+
module=Identifier("verification"),
|
|
533
|
+
cls_or_enum=None,
|
|
534
|
+
),
|
|
535
|
+
)
|
|
536
|
+
if docstring_errors is not None:
|
|
537
|
+
return None, Error(
|
|
538
|
+
verification.description.parsed.node,
|
|
539
|
+
"Failed to generate the docstring",
|
|
540
|
+
docstring_errors,
|
|
541
|
+
)
|
|
542
|
+
|
|
543
|
+
assert docstring is not None
|
|
544
|
+
|
|
545
|
+
writer.write("\n")
|
|
546
|
+
writer.write(textwrap.indent(docstring, I))
|
|
547
|
+
|
|
548
|
+
writer.write(f"\n{I}# pylint: disable=all")
|
|
549
|
+
|
|
550
|
+
if docstring is None and len(body) == 0:
|
|
551
|
+
writer.write(f"\n{I}pass")
|
|
552
|
+
|
|
553
|
+
for stmt in body:
|
|
554
|
+
writer.write("\n")
|
|
555
|
+
writer.write(textwrap.indent(stmt, I))
|
|
556
|
+
|
|
557
|
+
return Stripped(writer.getvalue()), None
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
class _InvariantTranspiler(python_transpilation.Transpiler):
|
|
561
|
+
def __init__(
|
|
562
|
+
self,
|
|
563
|
+
type_map: Mapping[
|
|
564
|
+
parse_tree.Node, intermediate_type_inference.TypeAnnotationUnion
|
|
565
|
+
],
|
|
566
|
+
environment: intermediate_type_inference.Environment,
|
|
567
|
+
symbol_table: intermediate.SymbolTable,
|
|
568
|
+
) -> None:
|
|
569
|
+
"""Initialize with the given values."""
|
|
570
|
+
python_transpilation.Transpiler.__init__(
|
|
571
|
+
self, type_map=type_map, environment=environment
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
self._symbol_table = symbol_table
|
|
575
|
+
|
|
576
|
+
def transform_name(
|
|
577
|
+
self, node: parse_tree.Name
|
|
578
|
+
) -> Tuple[Optional[Stripped], Optional[Error]]:
|
|
579
|
+
if node.identifier in self._variable_name_set:
|
|
580
|
+
return Stripped(python_naming.variable_name(node.identifier)), None
|
|
581
|
+
|
|
582
|
+
if node.identifier == "self":
|
|
583
|
+
# The ``that`` refers to the argument of the verification function.
|
|
584
|
+
return Stripped("that"), None
|
|
585
|
+
|
|
586
|
+
if node.identifier in self._symbol_table.constants_by_name:
|
|
587
|
+
constant_name = python_naming.constant_name(node.identifier)
|
|
588
|
+
return Stripped(f"aas_constants.{constant_name}"), None
|
|
589
|
+
|
|
590
|
+
if node.identifier in self._symbol_table.verification_functions_by_name:
|
|
591
|
+
return Stripped(python_naming.function_name(node.identifier)), None
|
|
592
|
+
|
|
593
|
+
our_type = self._symbol_table.find_our_type(name=node.identifier)
|
|
594
|
+
if isinstance(our_type, intermediate.Enumeration):
|
|
595
|
+
return (
|
|
596
|
+
Stripped(f"aas_types.{python_naming.enum_name(node.identifier)}"),
|
|
597
|
+
None,
|
|
598
|
+
)
|
|
599
|
+
|
|
600
|
+
return None, Error(
|
|
601
|
+
node.original_node,
|
|
602
|
+
f"We can not determine how to transpile the name {node.identifier!r} "
|
|
603
|
+
f"to Python. We could not find it neither in the local variables, "
|
|
604
|
+
f"nor in the global constants, nor in verification functions, "
|
|
605
|
+
f"nor as an enumeration. If you expect this name to be transpilable, "
|
|
606
|
+
f"please contact the developers.",
|
|
607
|
+
)
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
@ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
|
|
611
|
+
def _transpile_invariant(
|
|
612
|
+
invariant: intermediate.Invariant,
|
|
613
|
+
symbol_table: intermediate.SymbolTable,
|
|
614
|
+
environment: intermediate_type_inference.Environment,
|
|
615
|
+
) -> Tuple[Optional[Stripped], Optional[Error]]:
|
|
616
|
+
"""Translate the invariant from the meta-model into Python code."""
|
|
617
|
+
# fmt: off
|
|
618
|
+
type_map, inference_error = (
|
|
619
|
+
intermediate_type_inference.infer_for_invariant(
|
|
620
|
+
invariant=invariant,
|
|
621
|
+
environment=environment
|
|
622
|
+
)
|
|
623
|
+
)
|
|
624
|
+
# fmt: on
|
|
625
|
+
|
|
626
|
+
if inference_error is not None:
|
|
627
|
+
return None, inference_error
|
|
628
|
+
|
|
629
|
+
assert type_map is not None
|
|
630
|
+
|
|
631
|
+
transpiler = _InvariantTranspiler(
|
|
632
|
+
type_map=type_map,
|
|
633
|
+
environment=environment,
|
|
634
|
+
symbol_table=symbol_table,
|
|
635
|
+
)
|
|
636
|
+
|
|
637
|
+
expr, error = transpiler.transform(invariant.parsed.body)
|
|
638
|
+
if error is not None:
|
|
639
|
+
return None, error
|
|
640
|
+
|
|
641
|
+
assert expr is not None
|
|
642
|
+
|
|
643
|
+
writer = io.StringIO()
|
|
644
|
+
if len(expr) > 50 or "\n" in expr:
|
|
645
|
+
writer.write("if not (\n")
|
|
646
|
+
writer.write(textwrap.indent(expr, I))
|
|
647
|
+
writer.write("\n):\n")
|
|
648
|
+
else:
|
|
649
|
+
no_parenthesis_type_in_this_context = (
|
|
650
|
+
parse_tree.Index,
|
|
651
|
+
parse_tree.Name,
|
|
652
|
+
parse_tree.Member,
|
|
653
|
+
parse_tree.MethodCall,
|
|
654
|
+
parse_tree.FunctionCall,
|
|
655
|
+
)
|
|
656
|
+
|
|
657
|
+
if isinstance(invariant.parsed.body, no_parenthesis_type_in_this_context):
|
|
658
|
+
not_expr = f"not {expr}"
|
|
659
|
+
else:
|
|
660
|
+
not_expr = f"not ({expr})"
|
|
661
|
+
|
|
662
|
+
writer.write(f"if {not_expr}:\n")
|
|
663
|
+
|
|
664
|
+
writer.write(f"{I}yield Error(\n")
|
|
665
|
+
|
|
666
|
+
# NOTE (mristin, 2022-09-30):
|
|
667
|
+
# We need to wrap the description in multiple literals as a single long
|
|
668
|
+
# string literal is often too much for the readability.
|
|
669
|
+
invariant_description_lines = wrap_text_into_lines(invariant.description)
|
|
670
|
+
|
|
671
|
+
for i, literal in enumerate(invariant_description_lines):
|
|
672
|
+
if i < len(invariant_description_lines) - 1:
|
|
673
|
+
writer.write(f"{II}{python_common.string_literal(literal)} +\n")
|
|
674
|
+
else:
|
|
675
|
+
writer.write(f"{II}{python_common.string_literal(literal)}\n")
|
|
676
|
+
writer.write(f"{I})")
|
|
677
|
+
|
|
678
|
+
return Stripped(writer.getvalue()), None
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
OurTypeExceptEnumeration = Union[
|
|
682
|
+
intermediate.ConstrainedPrimitive,
|
|
683
|
+
intermediate.AbstractClass,
|
|
684
|
+
intermediate.ConcreteClass,
|
|
685
|
+
]
|
|
686
|
+
assert_union_without_excluded(
|
|
687
|
+
original_union=intermediate.OurType,
|
|
688
|
+
subset_union=OurTypeExceptEnumeration,
|
|
689
|
+
excluded=[intermediate.Enumeration],
|
|
690
|
+
)
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
@ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
|
|
694
|
+
def _generate_verify_property_snippet(
|
|
695
|
+
prop: intermediate.Property,
|
|
696
|
+
generator_for_loop_variables: python_common.GeneratorForLoopVariables,
|
|
697
|
+
) -> Tuple[Optional[Stripped], Optional[Error]]:
|
|
698
|
+
"""
|
|
699
|
+
Generate the snippet to transform a property to verification errors.
|
|
700
|
+
|
|
701
|
+
Return an empty string if there is nothing to be verified for the given property.
|
|
702
|
+
"""
|
|
703
|
+
# NOTE (mristin, 2022-10-01):
|
|
704
|
+
# Instead of writing here a complex but general solution with unrolling we choose
|
|
705
|
+
# to provide a simple, but limited, solution. First, the meta-model is quite
|
|
706
|
+
# limited itself at the moment, so the complexity of the general solution is not
|
|
707
|
+
# warranted. Second, we hope that there will be fewer bugs in the simple solution
|
|
708
|
+
# which is particularly important at this early adoption stage.
|
|
709
|
+
#
|
|
710
|
+
# We anticipate that in the future we will indeed need a general and complex
|
|
711
|
+
# solution. Here are just some thoughts on how to approach it:
|
|
712
|
+
# * Leave the pattern matching to produce more readable code for simple cases,
|
|
713
|
+
# * Unroll only in case of composite types and optional composite types.
|
|
714
|
+
|
|
715
|
+
type_anno = (
|
|
716
|
+
prop.type_annotation
|
|
717
|
+
if not isinstance(prop.type_annotation, intermediate.OptionalTypeAnnotation)
|
|
718
|
+
else prop.type_annotation.value
|
|
719
|
+
)
|
|
720
|
+
|
|
721
|
+
if isinstance(type_anno, intermediate.OptionalTypeAnnotation):
|
|
722
|
+
return None, Error(
|
|
723
|
+
prop.parsed.node,
|
|
724
|
+
"We currently implemented verification based on a very limited "
|
|
725
|
+
"pattern matching due to code simplicity. We did not handle "
|
|
726
|
+
"the case of nested optional values. Please contact "
|
|
727
|
+
"the developers if you need this functionality.",
|
|
728
|
+
)
|
|
729
|
+
elif isinstance(type_anno, intermediate.ListTypeAnnotation):
|
|
730
|
+
if isinstance(type_anno.items, intermediate.OptionalTypeAnnotation):
|
|
731
|
+
return None, Error(
|
|
732
|
+
prop.parsed.node,
|
|
733
|
+
"We currently implemented verification based on a very limited "
|
|
734
|
+
"pattern matching due to code simplicity. We did not handle "
|
|
735
|
+
"the case of lists of optional values. Please contact "
|
|
736
|
+
"the developers if you need this functionality.",
|
|
737
|
+
)
|
|
738
|
+
elif isinstance(type_anno.items, intermediate.ListTypeAnnotation):
|
|
739
|
+
return None, Error(
|
|
740
|
+
prop.parsed.node,
|
|
741
|
+
"We currently implemented verification based on a very limited "
|
|
742
|
+
"pattern matching due to code simplicity. We did not handle "
|
|
743
|
+
"the case of lists of lists. Please contact "
|
|
744
|
+
"the developers if you need this functionality.",
|
|
745
|
+
)
|
|
746
|
+
else:
|
|
747
|
+
pass
|
|
748
|
+
else:
|
|
749
|
+
pass
|
|
750
|
+
|
|
751
|
+
stmts = [] # type: List[Stripped]
|
|
752
|
+
|
|
753
|
+
prop_name = python_naming.property_name(prop.name)
|
|
754
|
+
prop_name_literal = python_common.string_literal(prop_name)
|
|
755
|
+
|
|
756
|
+
if isinstance(type_anno, intermediate.PrimitiveTypeAnnotation):
|
|
757
|
+
# There is nothing that we check for primitive types explicitly. The values
|
|
758
|
+
# of the primitive properties are checked at the level of class invariants.
|
|
759
|
+
return Stripped(""), None
|
|
760
|
+
elif isinstance(type_anno, intermediate.OurTypeAnnotation):
|
|
761
|
+
if isinstance(type_anno.our_type, intermediate.Enumeration):
|
|
762
|
+
# We rely on mypy to check for valid enumerations, so we do not check
|
|
763
|
+
# the enumerations on our side.
|
|
764
|
+
return Stripped(""), None
|
|
765
|
+
|
|
766
|
+
elif isinstance(type_anno.our_type, intermediate.ConstrainedPrimitive):
|
|
767
|
+
function_name = python_naming.function_name(
|
|
768
|
+
Identifier(f"verify_{type_anno.our_type.name}")
|
|
769
|
+
)
|
|
770
|
+
|
|
771
|
+
for_error_in_verify = f"for error in {function_name}(that.{prop_name})"
|
|
772
|
+
# Heuristic to break the lines, very rudimentary
|
|
773
|
+
if len(for_error_in_verify) > 70:
|
|
774
|
+
for_error_in_verify = f"""\
|
|
775
|
+
for error in {function_name}(
|
|
776
|
+
{II}that.{prop_name}
|
|
777
|
+
)"""
|
|
778
|
+
|
|
779
|
+
stmts.append(
|
|
780
|
+
Stripped(
|
|
781
|
+
f"""\
|
|
782
|
+
{for_error_in_verify}:
|
|
783
|
+
{I}error.path._prepend(
|
|
784
|
+
{II}PropertySegment(
|
|
785
|
+
{III}that,
|
|
786
|
+
{III}{prop_name_literal}
|
|
787
|
+
{II})
|
|
788
|
+
{I})
|
|
789
|
+
{I}yield error"""
|
|
790
|
+
)
|
|
791
|
+
)
|
|
792
|
+
|
|
793
|
+
elif isinstance(
|
|
794
|
+
type_anno.our_type, (intermediate.AbstractClass, intermediate.ConcreteClass)
|
|
795
|
+
):
|
|
796
|
+
for_error_in_self_transform = (
|
|
797
|
+
f"for error in self.transform(that.{prop_name})"
|
|
798
|
+
)
|
|
799
|
+
# Heuristic to break the lines, very rudimentary
|
|
800
|
+
if len(for_error_in_self_transform) > 70:
|
|
801
|
+
for_error_in_self_transform = f"""\
|
|
802
|
+
for error in self.transform(
|
|
803
|
+
{II}that.{prop_name}
|
|
804
|
+
)"""
|
|
805
|
+
|
|
806
|
+
stmts.append(
|
|
807
|
+
Stripped(
|
|
808
|
+
f"""\
|
|
809
|
+
{for_error_in_self_transform}:
|
|
810
|
+
{I}error.path._prepend(
|
|
811
|
+
{II}PropertySegment(
|
|
812
|
+
{III}that,
|
|
813
|
+
{III}{prop_name_literal}
|
|
814
|
+
{II})
|
|
815
|
+
{I})
|
|
816
|
+
{I}yield error"""
|
|
817
|
+
)
|
|
818
|
+
)
|
|
819
|
+
else:
|
|
820
|
+
assert_never(type_anno.our_type)
|
|
821
|
+
|
|
822
|
+
elif isinstance(type_anno, intermediate.ListTypeAnnotation):
|
|
823
|
+
assert not isinstance(
|
|
824
|
+
type_anno.items,
|
|
825
|
+
(intermediate.OptionalTypeAnnotation, intermediate.ListTypeAnnotation),
|
|
826
|
+
), (
|
|
827
|
+
"We chose to implement only a very limited pattern matching; "
|
|
828
|
+
"see the note above in the code."
|
|
829
|
+
)
|
|
830
|
+
|
|
831
|
+
# NOTE (mristin, 2022-10-01):
|
|
832
|
+
# We only descend into our classes here.
|
|
833
|
+
if not isinstance(type_anno.items, intermediate.OurTypeAnnotation):
|
|
834
|
+
return Stripped(""), None
|
|
835
|
+
|
|
836
|
+
loop_variable = next(generator_for_loop_variables)
|
|
837
|
+
|
|
838
|
+
for_i_item_in_that_prop = (
|
|
839
|
+
f"for i, {loop_variable} in enumerate(that.{prop_name})"
|
|
840
|
+
)
|
|
841
|
+
|
|
842
|
+
# Rudimentary heuristics for line breaking
|
|
843
|
+
if len(for_i_item_in_that_prop) > 70:
|
|
844
|
+
for_i_item_in_that_prop = f"""\
|
|
845
|
+
for i, {loop_variable} in enumerate(
|
|
846
|
+
{II}that.{prop_name}
|
|
847
|
+
)"""
|
|
848
|
+
|
|
849
|
+
for_error_in_self_transform = f"for error in self.transform({loop_variable})"
|
|
850
|
+
if len(for_error_in_self_transform) > 70:
|
|
851
|
+
for_error_in_self_transform = f"""\
|
|
852
|
+
for error in self.transform(
|
|
853
|
+
{II}{loop_variable}
|
|
854
|
+
)"""
|
|
855
|
+
|
|
856
|
+
stmts.append(
|
|
857
|
+
Stripped(
|
|
858
|
+
f"""\
|
|
859
|
+
{for_i_item_in_that_prop}:
|
|
860
|
+
{I}{indent_but_first_line(for_error_in_self_transform, I)}:
|
|
861
|
+
{II}error.path._prepend(
|
|
862
|
+
{III}IndexSegment(
|
|
863
|
+
{IIII}that.{prop_name},
|
|
864
|
+
{IIII}i
|
|
865
|
+
{III})
|
|
866
|
+
{II})
|
|
867
|
+
{II}error.path._prepend(
|
|
868
|
+
{III}PropertySegment(
|
|
869
|
+
{IIII}that,
|
|
870
|
+
{IIII}{prop_name_literal}
|
|
871
|
+
{III})
|
|
872
|
+
{II})
|
|
873
|
+
{II}yield error"""
|
|
874
|
+
)
|
|
875
|
+
)
|
|
876
|
+
|
|
877
|
+
else:
|
|
878
|
+
assert_never(type_anno)
|
|
879
|
+
|
|
880
|
+
verify_block = Stripped("\n".join(stmts))
|
|
881
|
+
|
|
882
|
+
if isinstance(prop.type_annotation, intermediate.OptionalTypeAnnotation):
|
|
883
|
+
return (
|
|
884
|
+
Stripped(
|
|
885
|
+
f"""\
|
|
886
|
+
if that.{prop_name} is not None:
|
|
887
|
+
{I}{indent_but_first_line(verify_block, I)}"""
|
|
888
|
+
),
|
|
889
|
+
None,
|
|
890
|
+
)
|
|
891
|
+
|
|
892
|
+
return verify_block, None
|
|
893
|
+
|
|
894
|
+
|
|
895
|
+
@ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
|
|
896
|
+
def _generate_transform_for_class(
|
|
897
|
+
cls: intermediate.ConcreteClass,
|
|
898
|
+
symbol_table: intermediate.SymbolTable,
|
|
899
|
+
base_environment: intermediate_type_inference.Environment,
|
|
900
|
+
) -> Tuple[Optional[Stripped], Optional[List[Error]]]:
|
|
901
|
+
"""Generate the transform method to errors for the given concrete class."""
|
|
902
|
+
errors = [] # type: List[Error]
|
|
903
|
+
blocks = [] # type: List[Stripped]
|
|
904
|
+
|
|
905
|
+
environment = intermediate_type_inference.MutableEnvironment(
|
|
906
|
+
parent=base_environment
|
|
907
|
+
)
|
|
908
|
+
|
|
909
|
+
assert environment.find(Identifier("self")) is None
|
|
910
|
+
environment.set(
|
|
911
|
+
identifier=Identifier("self"),
|
|
912
|
+
type_annotation=intermediate_type_inference.OurTypeAnnotation(our_type=cls),
|
|
913
|
+
)
|
|
914
|
+
|
|
915
|
+
for invariant in cls.invariants:
|
|
916
|
+
invariant_code, error = _transpile_invariant(
|
|
917
|
+
invariant=invariant, symbol_table=symbol_table, environment=environment
|
|
918
|
+
)
|
|
919
|
+
if error is not None:
|
|
920
|
+
errors.append(
|
|
921
|
+
Error(
|
|
922
|
+
cls.parsed.node,
|
|
923
|
+
f"Failed to transpile the invariant of the class {cls.name!r}",
|
|
924
|
+
[error],
|
|
925
|
+
)
|
|
926
|
+
)
|
|
927
|
+
continue
|
|
928
|
+
|
|
929
|
+
assert invariant_code is not None
|
|
930
|
+
|
|
931
|
+
blocks.append(invariant_code)
|
|
932
|
+
|
|
933
|
+
if len(errors) > 0:
|
|
934
|
+
return None, errors
|
|
935
|
+
|
|
936
|
+
# NOTE (mristin, 2022-10-14):
|
|
937
|
+
# We need to generate unique loop variable for each loop since Python tracks
|
|
938
|
+
# the variables in function scope, not block scope.
|
|
939
|
+
generator_for_loop_variables = python_common.GeneratorForLoopVariables()
|
|
940
|
+
|
|
941
|
+
for prop in cls.properties:
|
|
942
|
+
block, error = _generate_verify_property_snippet(
|
|
943
|
+
prop=prop, generator_for_loop_variables=generator_for_loop_variables
|
|
944
|
+
)
|
|
945
|
+
if error is not None:
|
|
946
|
+
errors.append(error)
|
|
947
|
+
else:
|
|
948
|
+
assert block is not None
|
|
949
|
+
if block != "":
|
|
950
|
+
blocks.append(block)
|
|
951
|
+
|
|
952
|
+
if len(errors) > 0:
|
|
953
|
+
return None, errors
|
|
954
|
+
|
|
955
|
+
cls_name = python_naming.class_name(cls.name)
|
|
956
|
+
|
|
957
|
+
if len(blocks) == 0:
|
|
958
|
+
blocks.append(
|
|
959
|
+
Stripped(
|
|
960
|
+
f"""\
|
|
961
|
+
# No verification has been defined for {cls_name}.
|
|
962
|
+
return
|
|
963
|
+
# For this uncommon return-yield construction, see:
|
|
964
|
+
# https://stackoverflow.com/questions/13243766/how-to-define-an-empty-generator-function
|
|
965
|
+
# noinspection PyUnreachableCode
|
|
966
|
+
yield"""
|
|
967
|
+
)
|
|
968
|
+
)
|
|
969
|
+
|
|
970
|
+
transform_name = python_naming.method_name(Identifier(f"transform_{cls.name}"))
|
|
971
|
+
|
|
972
|
+
writer = io.StringIO()
|
|
973
|
+
writer.write(
|
|
974
|
+
f"""\
|
|
975
|
+
# noinspection PyMethodMayBeStatic
|
|
976
|
+
def {transform_name}(
|
|
977
|
+
{II}self,
|
|
978
|
+
{II}that: aas_types.{cls_name}
|
|
979
|
+
) -> Iterator[Error]:
|
|
980
|
+
"""
|
|
981
|
+
)
|
|
982
|
+
|
|
983
|
+
for i, stmt in enumerate(blocks):
|
|
984
|
+
if i > 0:
|
|
985
|
+
writer.write("\n\n")
|
|
986
|
+
writer.write(textwrap.indent(stmt, I))
|
|
987
|
+
|
|
988
|
+
return Stripped(writer.getvalue()), None
|
|
989
|
+
|
|
990
|
+
|
|
991
|
+
def _generate_transformer(
|
|
992
|
+
symbol_table: intermediate.SymbolTable,
|
|
993
|
+
base_environment: intermediate_type_inference.Environment,
|
|
994
|
+
spec_impls: specific_implementations.SpecificImplementations,
|
|
995
|
+
) -> Tuple[Optional[Stripped], Optional[List[Error]]]:
|
|
996
|
+
"""Generate a transformer to double-dispatch an instance to errors."""
|
|
997
|
+
errors = [] # type: List[Error]
|
|
998
|
+
|
|
999
|
+
blocks = [] # type: List[Stripped]
|
|
1000
|
+
|
|
1001
|
+
# The abstract classes are directly dispatched by the transformer,
|
|
1002
|
+
# so we do not need to handle them separately.
|
|
1003
|
+
|
|
1004
|
+
for cls in symbol_table.concrete_classes:
|
|
1005
|
+
if cls.is_implementation_specific:
|
|
1006
|
+
transform_key = specific_implementations.ImplementationKey(
|
|
1007
|
+
f"Verification/transform_{cls.name}.py"
|
|
1008
|
+
)
|
|
1009
|
+
|
|
1010
|
+
implementation = spec_impls.get(transform_key, None)
|
|
1011
|
+
if implementation is None:
|
|
1012
|
+
errors.append(
|
|
1013
|
+
Error(
|
|
1014
|
+
cls.parsed.node,
|
|
1015
|
+
f"The transformation snippet is missing "
|
|
1016
|
+
f"for the implementation-specific "
|
|
1017
|
+
f"class {cls.name}: {transform_key}",
|
|
1018
|
+
)
|
|
1019
|
+
)
|
|
1020
|
+
continue
|
|
1021
|
+
|
|
1022
|
+
blocks.append(spec_impls[transform_key])
|
|
1023
|
+
else:
|
|
1024
|
+
block, cls_errors = _generate_transform_for_class(
|
|
1025
|
+
cls=cls,
|
|
1026
|
+
symbol_table=symbol_table,
|
|
1027
|
+
base_environment=base_environment,
|
|
1028
|
+
)
|
|
1029
|
+
if cls_errors is not None:
|
|
1030
|
+
errors.extend(cls_errors)
|
|
1031
|
+
else:
|
|
1032
|
+
assert block is not None
|
|
1033
|
+
blocks.append(block)
|
|
1034
|
+
|
|
1035
|
+
if len(errors) > 0:
|
|
1036
|
+
return None, errors
|
|
1037
|
+
|
|
1038
|
+
writer = io.StringIO()
|
|
1039
|
+
writer.write(
|
|
1040
|
+
f"""\
|
|
1041
|
+
class _Transformer(
|
|
1042
|
+
{II}aas_types.AbstractTransformer[
|
|
1043
|
+
{III}Iterator[Error]
|
|
1044
|
+
{II}]
|
|
1045
|
+
):
|
|
1046
|
+
"""
|
|
1047
|
+
)
|
|
1048
|
+
|
|
1049
|
+
for i, block in enumerate(blocks):
|
|
1050
|
+
if i > 0:
|
|
1051
|
+
writer.write("\n\n")
|
|
1052
|
+
writer.write(textwrap.indent(block, I))
|
|
1053
|
+
|
|
1054
|
+
return Stripped(writer.getvalue()), None
|
|
1055
|
+
|
|
1056
|
+
|
|
1057
|
+
def _generate_verify_constrained_primitive(
|
|
1058
|
+
constrained_primitive: intermediate.ConstrainedPrimitive,
|
|
1059
|
+
symbol_table: intermediate.SymbolTable,
|
|
1060
|
+
base_environment: intermediate_type_inference.Environment,
|
|
1061
|
+
) -> Tuple[Optional[Stripped], Optional[List[Error]]]:
|
|
1062
|
+
"""Generate the verify function for the constrained primitives."""
|
|
1063
|
+
errors = [] # type: List[Error]
|
|
1064
|
+
blocks = [] # type: List[Stripped]
|
|
1065
|
+
|
|
1066
|
+
environment = intermediate_type_inference.MutableEnvironment(
|
|
1067
|
+
parent=base_environment
|
|
1068
|
+
)
|
|
1069
|
+
|
|
1070
|
+
assert environment.find(Identifier("self")) is None
|
|
1071
|
+
environment.set(
|
|
1072
|
+
identifier=Identifier("self"),
|
|
1073
|
+
type_annotation=intermediate_type_inference.OurTypeAnnotation(
|
|
1074
|
+
our_type=constrained_primitive
|
|
1075
|
+
),
|
|
1076
|
+
)
|
|
1077
|
+
|
|
1078
|
+
for invariant in constrained_primitive.invariants:
|
|
1079
|
+
invariant_code, error = _transpile_invariant(
|
|
1080
|
+
invariant=invariant, symbol_table=symbol_table, environment=environment
|
|
1081
|
+
)
|
|
1082
|
+
if error is not None:
|
|
1083
|
+
errors.append(
|
|
1084
|
+
Error(
|
|
1085
|
+
constrained_primitive.parsed.node,
|
|
1086
|
+
f"Failed to transpile the invariant of "
|
|
1087
|
+
f"the constrained primitive {constrained_primitive.name!r}",
|
|
1088
|
+
[error],
|
|
1089
|
+
)
|
|
1090
|
+
)
|
|
1091
|
+
continue
|
|
1092
|
+
|
|
1093
|
+
assert invariant_code is not None
|
|
1094
|
+
|
|
1095
|
+
blocks.append(invariant_code)
|
|
1096
|
+
|
|
1097
|
+
if len(errors) > 0:
|
|
1098
|
+
return None, errors
|
|
1099
|
+
|
|
1100
|
+
no_verification_specified = False
|
|
1101
|
+
if len(blocks) == 0:
|
|
1102
|
+
no_verification_specified = True
|
|
1103
|
+
blocks.append(
|
|
1104
|
+
Stripped(
|
|
1105
|
+
"""\
|
|
1106
|
+
# There is no verification specified.
|
|
1107
|
+
return
|
|
1108
|
+
|
|
1109
|
+
# Empty generator according to:
|
|
1110
|
+
# https://stackoverflow.com/a/13243870/1600678
|
|
1111
|
+
# noinspection PyUnreachableCode
|
|
1112
|
+
yield"""
|
|
1113
|
+
)
|
|
1114
|
+
)
|
|
1115
|
+
|
|
1116
|
+
function_name = python_naming.function_name(
|
|
1117
|
+
Identifier(f"verify_{constrained_primitive.name}")
|
|
1118
|
+
)
|
|
1119
|
+
|
|
1120
|
+
that_type = python_common.PRIMITIVE_TYPE_MAP[constrained_primitive.constrainee]
|
|
1121
|
+
|
|
1122
|
+
writer = io.StringIO()
|
|
1123
|
+
|
|
1124
|
+
if no_verification_specified:
|
|
1125
|
+
# NOTE (mristin, 2022-10-02):
|
|
1126
|
+
# We provide a function for evolvability even though it does nothing.
|
|
1127
|
+
writer.write("# noinspection PyUnusedLocal\n")
|
|
1128
|
+
|
|
1129
|
+
writer.write(
|
|
1130
|
+
f"""\
|
|
1131
|
+
def {function_name}(
|
|
1132
|
+
{II}that: {that_type}
|
|
1133
|
+
) -> Iterator[Error]:
|
|
1134
|
+
{I}\"\"\"Verify the constraints of :paramref:`that`.\"\"\"
|
|
1135
|
+
"""
|
|
1136
|
+
)
|
|
1137
|
+
|
|
1138
|
+
for i, block in enumerate(blocks):
|
|
1139
|
+
if i > 0:
|
|
1140
|
+
writer.write("\n\n")
|
|
1141
|
+
writer.write(textwrap.indent(block, I))
|
|
1142
|
+
|
|
1143
|
+
assert len(errors) == 0
|
|
1144
|
+
return Stripped(writer.getvalue()), None
|
|
1145
|
+
|
|
1146
|
+
|
|
1147
|
+
def _generate_module_docstring(
|
|
1148
|
+
symbol_table: intermediate.SymbolTable,
|
|
1149
|
+
aas_module: python_common.QualifiedModuleName,
|
|
1150
|
+
) -> Stripped:
|
|
1151
|
+
"""Generate the docstring for the module."""
|
|
1152
|
+
docstring_blocks = [
|
|
1153
|
+
Stripped("Verify that the instances of the meta-model satisfy the invariants.")
|
|
1154
|
+
] # type: List[Stripped]
|
|
1155
|
+
|
|
1156
|
+
first_cls = (
|
|
1157
|
+
symbol_table.concrete_classes[0]
|
|
1158
|
+
if len(symbol_table.concrete_classes) > 0
|
|
1159
|
+
else None
|
|
1160
|
+
) # type: Optional[intermediate.ConcreteClass]
|
|
1161
|
+
|
|
1162
|
+
if first_cls is not None:
|
|
1163
|
+
cls_name = python_naming.class_name(first_cls.name)
|
|
1164
|
+
an_instance_variable = python_naming.variable_name(Identifier("an_instance"))
|
|
1165
|
+
|
|
1166
|
+
docstring_blocks.append(
|
|
1167
|
+
Stripped(
|
|
1168
|
+
f"""\
|
|
1169
|
+
Here is an example how to verify an instance of :py:class:`{aas_module}.types.{cls_name}`:
|
|
1170
|
+
|
|
1171
|
+
.. code-block::
|
|
1172
|
+
|
|
1173
|
+
import {aas_module}.types as aas_types
|
|
1174
|
+
import {aas_module}.verification as aas_verification
|
|
1175
|
+
|
|
1176
|
+
{an_instance_variable} = aas_types.{cls_name}(
|
|
1177
|
+
# ... some constructor arguments ...
|
|
1178
|
+
)
|
|
1179
|
+
|
|
1180
|
+
for error in aas_verification.verify({an_instance_variable}):
|
|
1181
|
+
print(f"{{error.cause}} at: {{error.path}}")"""
|
|
1182
|
+
)
|
|
1183
|
+
)
|
|
1184
|
+
|
|
1185
|
+
# endregion
|
|
1186
|
+
|
|
1187
|
+
if len(docstring_blocks) == 1:
|
|
1188
|
+
doc_escaped = docstring_blocks[0].replace('"""', '\\"\\"\\"')
|
|
1189
|
+
docstring = f'"""{doc_escaped}"""'
|
|
1190
|
+
else:
|
|
1191
|
+
doc_escaped = ("\n\n".join(docstring_blocks)).replace('"""', '\\"\\"\\"')
|
|
1192
|
+
docstring = f'''\
|
|
1193
|
+
"""
|
|
1194
|
+
{doc_escaped}
|
|
1195
|
+
"""'''
|
|
1196
|
+
|
|
1197
|
+
return Stripped(docstring)
|
|
1198
|
+
|
|
1199
|
+
|
|
1200
|
+
# fmt: off
|
|
1201
|
+
@ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
|
|
1202
|
+
@ensure(
|
|
1203
|
+
lambda result:
|
|
1204
|
+
not (result[0] is not None) or result[0].endswith('\n'),
|
|
1205
|
+
"Trailing newline mandatory for valid end-of-files"
|
|
1206
|
+
)
|
|
1207
|
+
# fmt: on
|
|
1208
|
+
def generate(
|
|
1209
|
+
symbol_table: intermediate.SymbolTable,
|
|
1210
|
+
aas_module: python_common.QualifiedModuleName,
|
|
1211
|
+
spec_impls: specific_implementations.SpecificImplementations,
|
|
1212
|
+
) -> Tuple[Optional[str], Optional[List[Error]]]:
|
|
1213
|
+
"""
|
|
1214
|
+
Generate the Python code for verification based on the symbol table.
|
|
1215
|
+
|
|
1216
|
+
The ``aas_module`` indicates the fully-qualified name of the base module.
|
|
1217
|
+
"""
|
|
1218
|
+
# region Module docstring
|
|
1219
|
+
blocks = [
|
|
1220
|
+
_generate_module_docstring(symbol_table=symbol_table, aas_module=aas_module),
|
|
1221
|
+
python_common.WARNING,
|
|
1222
|
+
Stripped(
|
|
1223
|
+
f"""\
|
|
1224
|
+
import math
|
|
1225
|
+
import re
|
|
1226
|
+
import struct
|
|
1227
|
+
import sys
|
|
1228
|
+
from typing import (
|
|
1229
|
+
{I}Callable,
|
|
1230
|
+
{I}Iterable,
|
|
1231
|
+
{I}Iterator,
|
|
1232
|
+
{I}List,
|
|
1233
|
+
{I}Mapping,
|
|
1234
|
+
{I}Optional,
|
|
1235
|
+
{I}Pattern,
|
|
1236
|
+
{I}Sequence,
|
|
1237
|
+
{I}Set,
|
|
1238
|
+
{I}Union
|
|
1239
|
+
)
|
|
1240
|
+
|
|
1241
|
+
if sys.version_info >= (3, 8):
|
|
1242
|
+
{I}from typing import Final
|
|
1243
|
+
else:
|
|
1244
|
+
{I}from typing_extensions import Final
|
|
1245
|
+
|
|
1246
|
+
from {aas_module} import (
|
|
1247
|
+
{I}constants as aas_constants,
|
|
1248
|
+
{I}types as aas_types,
|
|
1249
|
+
)"""
|
|
1250
|
+
),
|
|
1251
|
+
Stripped(
|
|
1252
|
+
f"""\
|
|
1253
|
+
class PropertySegment:
|
|
1254
|
+
{I}\"\"\"Represent a property access on a path to an erroneous value.\"\"\"
|
|
1255
|
+
|
|
1256
|
+
{I}#: Instance containing the property
|
|
1257
|
+
{I}instance: Final[aas_types.Class]
|
|
1258
|
+
|
|
1259
|
+
{I}#: Name of the property
|
|
1260
|
+
{I}name: Final[str]
|
|
1261
|
+
|
|
1262
|
+
{I}def __init__(
|
|
1263
|
+
{III}self,
|
|
1264
|
+
{III}instance: aas_types.Class,
|
|
1265
|
+
{III}name: str
|
|
1266
|
+
{I}) -> None:
|
|
1267
|
+
{II}\"\"\"Initialize with the given values.\"\"\"
|
|
1268
|
+
{II}self.instance = instance
|
|
1269
|
+
{II}self.name = name
|
|
1270
|
+
|
|
1271
|
+
{I}def __str__(self) -> str:
|
|
1272
|
+
{II}return f'.{{self.name}}'"""
|
|
1273
|
+
),
|
|
1274
|
+
Stripped(
|
|
1275
|
+
f"""\
|
|
1276
|
+
class IndexSegment:
|
|
1277
|
+
{I}\"\"\"Represent an index access on a path to an erroneous value.\"\"\"
|
|
1278
|
+
|
|
1279
|
+
{I}#: Sequence containing the item at :py:attr:`~index`
|
|
1280
|
+
{I}sequence: Final[Sequence[aas_types.Class]]
|
|
1281
|
+
|
|
1282
|
+
{I}#: Index of the item
|
|
1283
|
+
{I}index: Final[int]
|
|
1284
|
+
|
|
1285
|
+
{I}def __init__(
|
|
1286
|
+
{III}self,
|
|
1287
|
+
{III}sequence: Sequence[aas_types.Class],
|
|
1288
|
+
{III}index: int
|
|
1289
|
+
{I}) -> None:
|
|
1290
|
+
{II}\"\"\"Initialize with the given values.\"\"\"
|
|
1291
|
+
{II}self.sequence = sequence
|
|
1292
|
+
{II}self.index = index
|
|
1293
|
+
|
|
1294
|
+
{I}def __str__(self) -> str:
|
|
1295
|
+
{II}return f'[{{self.index}}]'"""
|
|
1296
|
+
),
|
|
1297
|
+
Stripped("Segment = Union[PropertySegment, IndexSegment]"),
|
|
1298
|
+
Stripped(
|
|
1299
|
+
f"""\
|
|
1300
|
+
class Path:
|
|
1301
|
+
{I}\"\"\"Represent the relative path to the erroneous value.\"\"\"
|
|
1302
|
+
|
|
1303
|
+
{I}def __init__(self) -> None:
|
|
1304
|
+
{II}\"\"\"Initialize as an empty path.\"\"\"
|
|
1305
|
+
{II}self._segments = [] # type: List[Segment]
|
|
1306
|
+
|
|
1307
|
+
{I}@property
|
|
1308
|
+
{I}def segments(self) -> Sequence[Segment]:
|
|
1309
|
+
{II}\"\"\"Get the segments of the path.\"\"\"
|
|
1310
|
+
{II}return self._segments
|
|
1311
|
+
|
|
1312
|
+
{I}def _prepend(self, segment: Segment) -> None:
|
|
1313
|
+
{II}\"\"\"Insert the :paramref:`segment` in front of other segments.\"\"\"
|
|
1314
|
+
{II}self._segments.insert(0, segment)
|
|
1315
|
+
|
|
1316
|
+
{I}def __str__(self) -> str:
|
|
1317
|
+
{II}return "".join(str(segment) for segment in self._segments)"""
|
|
1318
|
+
),
|
|
1319
|
+
Stripped(
|
|
1320
|
+
f"""\
|
|
1321
|
+
class Error:
|
|
1322
|
+
{I}\"\"\"Represent a verification error in the data.\"\"\"
|
|
1323
|
+
|
|
1324
|
+
{I}#: Human-readable description of the error
|
|
1325
|
+
{I}cause: Final[str]
|
|
1326
|
+
|
|
1327
|
+
{I}#: Path to the erroneous value
|
|
1328
|
+
{I}path: Final[Path]
|
|
1329
|
+
|
|
1330
|
+
{I}def __init__(self, cause: str) -> None:
|
|
1331
|
+
{II}\"\"\"Initialize as an error with an empty path.\"\"\"
|
|
1332
|
+
{II}self.cause = cause
|
|
1333
|
+
{II}self.path = Path()
|
|
1334
|
+
|
|
1335
|
+
{I}def __repr__(self) -> str:
|
|
1336
|
+
{II}return f"Error(path={{self.path}}, cause={{self.cause}})\""""
|
|
1337
|
+
),
|
|
1338
|
+
] # type: List[Stripped]
|
|
1339
|
+
|
|
1340
|
+
errors = [] # type: List[Error]
|
|
1341
|
+
|
|
1342
|
+
base_environment = intermediate_type_inference.populate_base_environment(
|
|
1343
|
+
symbol_table=symbol_table
|
|
1344
|
+
)
|
|
1345
|
+
|
|
1346
|
+
for verification in symbol_table.verification_functions:
|
|
1347
|
+
if isinstance(verification, intermediate.ImplementationSpecificVerification):
|
|
1348
|
+
implementation_key = specific_implementations.ImplementationKey(
|
|
1349
|
+
f"Verification/{verification.name}.py"
|
|
1350
|
+
)
|
|
1351
|
+
|
|
1352
|
+
implementation = spec_impls.get(implementation_key, None)
|
|
1353
|
+
if implementation is None:
|
|
1354
|
+
errors.append(
|
|
1355
|
+
Error(
|
|
1356
|
+
None,
|
|
1357
|
+
f"The snippet for the verification function "
|
|
1358
|
+
f"{verification.name!r} is missing: {implementation_key}",
|
|
1359
|
+
)
|
|
1360
|
+
)
|
|
1361
|
+
else:
|
|
1362
|
+
blocks.append(implementation)
|
|
1363
|
+
|
|
1364
|
+
elif isinstance(verification, intermediate.PatternVerification):
|
|
1365
|
+
implementation, error = _transpile_pattern_verification(
|
|
1366
|
+
verification=verification, aas_module=aas_module
|
|
1367
|
+
)
|
|
1368
|
+
|
|
1369
|
+
if error is not None:
|
|
1370
|
+
errors.append(error)
|
|
1371
|
+
else:
|
|
1372
|
+
assert implementation is not None
|
|
1373
|
+
blocks.append(implementation)
|
|
1374
|
+
|
|
1375
|
+
elif isinstance(verification, intermediate.TranspilableVerification):
|
|
1376
|
+
implementation, error = _transpile_transpilable_verification(
|
|
1377
|
+
verification=verification,
|
|
1378
|
+
symbol_table=symbol_table,
|
|
1379
|
+
environment=base_environment,
|
|
1380
|
+
aas_module=aas_module,
|
|
1381
|
+
)
|
|
1382
|
+
|
|
1383
|
+
if error is not None:
|
|
1384
|
+
errors.append(error)
|
|
1385
|
+
else:
|
|
1386
|
+
assert implementation is not None
|
|
1387
|
+
blocks.append(implementation)
|
|
1388
|
+
|
|
1389
|
+
else:
|
|
1390
|
+
assert_never(verification)
|
|
1391
|
+
|
|
1392
|
+
transformer_block, transformer_errors = _generate_transformer(
|
|
1393
|
+
symbol_table=symbol_table,
|
|
1394
|
+
base_environment=base_environment,
|
|
1395
|
+
spec_impls=spec_impls,
|
|
1396
|
+
)
|
|
1397
|
+
if transformer_errors is not None:
|
|
1398
|
+
errors.extend(transformer_errors)
|
|
1399
|
+
else:
|
|
1400
|
+
assert transformer_block is not None
|
|
1401
|
+
blocks.append(transformer_block)
|
|
1402
|
+
|
|
1403
|
+
blocks.append(Stripped("_TRANSFORMER = _Transformer()"))
|
|
1404
|
+
|
|
1405
|
+
blocks.append(
|
|
1406
|
+
Stripped(
|
|
1407
|
+
f"""\
|
|
1408
|
+
def verify(
|
|
1409
|
+
{II}that: aas_types.Class
|
|
1410
|
+
) -> Iterator[Error]:
|
|
1411
|
+
{I}\"\"\"
|
|
1412
|
+
{I}Verify the constraints of :paramref:`that` recursively.
|
|
1413
|
+
|
|
1414
|
+
{I}:param that: instance whose constraints we want to verify
|
|
1415
|
+
{I}:yield: constraint violations
|
|
1416
|
+
{I}\"\"\"
|
|
1417
|
+
{I}yield from _TRANSFORMER.transform(that)"""
|
|
1418
|
+
)
|
|
1419
|
+
)
|
|
1420
|
+
|
|
1421
|
+
for our_type in symbol_table.our_types:
|
|
1422
|
+
if isinstance(our_type, intermediate.Enumeration):
|
|
1423
|
+
# NOTE (mristin, 2022-10-01):
|
|
1424
|
+
# We do not verify the enumerations explicitly in Python as mypy
|
|
1425
|
+
# is capable enough to spot invalid enum literals.
|
|
1426
|
+
pass
|
|
1427
|
+
|
|
1428
|
+
elif isinstance(our_type, intermediate.ConstrainedPrimitive):
|
|
1429
|
+
(
|
|
1430
|
+
constrained_primitive_block,
|
|
1431
|
+
constrained_primitive_errors,
|
|
1432
|
+
) = _generate_verify_constrained_primitive(
|
|
1433
|
+
constrained_primitive=our_type,
|
|
1434
|
+
symbol_table=symbol_table,
|
|
1435
|
+
base_environment=base_environment,
|
|
1436
|
+
)
|
|
1437
|
+
|
|
1438
|
+
if constrained_primitive_errors is not None:
|
|
1439
|
+
errors.extend(constrained_primitive_errors)
|
|
1440
|
+
else:
|
|
1441
|
+
assert constrained_primitive_block is not None
|
|
1442
|
+
blocks.append(constrained_primitive_block)
|
|
1443
|
+
|
|
1444
|
+
elif isinstance(
|
|
1445
|
+
our_type, (intermediate.AbstractClass, intermediate.ConcreteClass)
|
|
1446
|
+
):
|
|
1447
|
+
# NOTE (mristin, 2022-10-01):
|
|
1448
|
+
# We provide a general dispatch function for the most abstract
|
|
1449
|
+
# class ``Class``.
|
|
1450
|
+
pass
|
|
1451
|
+
else:
|
|
1452
|
+
assert_never(our_type)
|
|
1453
|
+
|
|
1454
|
+
blocks.append(python_common.WARNING)
|
|
1455
|
+
|
|
1456
|
+
if len(errors) > 0:
|
|
1457
|
+
return None, errors
|
|
1458
|
+
|
|
1459
|
+
writer = io.StringIO()
|
|
1460
|
+
for i, block in enumerate(blocks):
|
|
1461
|
+
if i > 0:
|
|
1462
|
+
writer.write("\n\n\n")
|
|
1463
|
+
|
|
1464
|
+
writer.write(block)
|
|
1465
|
+
|
|
1466
|
+
writer.write("\n")
|
|
1467
|
+
|
|
1468
|
+
return writer.getvalue(), None
|
|
1469
|
+
|
|
1470
|
+
|
|
1471
|
+
# endregion
|