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,2619 @@
|
|
|
1
|
+
"""Generate C++ code for de/serialization of instances from JSON."""
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
import itertools
|
|
5
|
+
from typing import List, Tuple, Optional, Iterable
|
|
6
|
+
|
|
7
|
+
from icontract import ensure, require
|
|
8
|
+
|
|
9
|
+
from aas_core_codegen import intermediate, specific_implementations, naming
|
|
10
|
+
from aas_core_codegen.common import (
|
|
11
|
+
Stripped,
|
|
12
|
+
indent_but_first_line,
|
|
13
|
+
Identifier,
|
|
14
|
+
Error,
|
|
15
|
+
assert_never,
|
|
16
|
+
)
|
|
17
|
+
from aas_core_codegen.cpp import common as cpp_common, naming as cpp_naming
|
|
18
|
+
from aas_core_codegen.cpp.common import (
|
|
19
|
+
INDENT as I,
|
|
20
|
+
INDENT2 as II,
|
|
21
|
+
INDENT3 as III,
|
|
22
|
+
INDENT4 as IIII,
|
|
23
|
+
INDENT5 as IIIII,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _generate_deserialization_definitions(
|
|
28
|
+
symbol_table: intermediate.SymbolTable,
|
|
29
|
+
) -> List[Stripped]:
|
|
30
|
+
"""Generate the definitions of deserialization functions."""
|
|
31
|
+
blocks = [] # type: List[Stripped]
|
|
32
|
+
|
|
33
|
+
for cls in symbol_table.classes:
|
|
34
|
+
interface_name = cpp_naming.interface_name(cls.name)
|
|
35
|
+
deserialization_name = cpp_naming.function_name(Identifier(f"{cls.name}_from"))
|
|
36
|
+
|
|
37
|
+
blocks.append(
|
|
38
|
+
Stripped(
|
|
39
|
+
f"""\
|
|
40
|
+
/**
|
|
41
|
+
* \\brief Deserialize \\p json value to an instance
|
|
42
|
+
* of types::{interface_name}.
|
|
43
|
+
*
|
|
44
|
+
* \\param json value to be de-serialized
|
|
45
|
+
* \\param additional_properties if not set, check that \\p json contains
|
|
46
|
+
* no additional properties
|
|
47
|
+
* \\return The deserialized instance, or a de-serialization error, if any.
|
|
48
|
+
*/
|
|
49
|
+
common::expected<
|
|
50
|
+
{I}std::shared_ptr<types::{interface_name}>,
|
|
51
|
+
{I}DeserializationError
|
|
52
|
+
> {deserialization_name}(
|
|
53
|
+
{I}const nlohmann::json& json,
|
|
54
|
+
{I}bool additional_properties = false
|
|
55
|
+
);"""
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
return blocks
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# fmt: off
|
|
63
|
+
@ensure(
|
|
64
|
+
lambda result:
|
|
65
|
+
result.endswith('\n'),
|
|
66
|
+
"Trailing newline mandatory for valid end-of-files"
|
|
67
|
+
)
|
|
68
|
+
# fmt: on
|
|
69
|
+
def generate_header(
|
|
70
|
+
symbol_table: intermediate.SymbolTable, library_namespace: Stripped
|
|
71
|
+
) -> str:
|
|
72
|
+
"""Generate the C++ header code for JSON de/serialization."""
|
|
73
|
+
namespace = Stripped(f"{library_namespace}::{cpp_common.JSONIZATION_NAMESPACE}")
|
|
74
|
+
|
|
75
|
+
include_guard_var = cpp_common.include_guard_var(namespace)
|
|
76
|
+
|
|
77
|
+
include_prefix_path = cpp_common.generate_include_prefix_path(library_namespace)
|
|
78
|
+
|
|
79
|
+
blocks = [
|
|
80
|
+
Stripped(
|
|
81
|
+
f"""\
|
|
82
|
+
#ifndef {include_guard_var}
|
|
83
|
+
#define {include_guard_var}"""
|
|
84
|
+
),
|
|
85
|
+
cpp_common.WARNING,
|
|
86
|
+
Stripped(
|
|
87
|
+
f"""\
|
|
88
|
+
#include "{include_prefix_path}/common.hpp"
|
|
89
|
+
#include "{include_prefix_path}/iteration.hpp"
|
|
90
|
+
#include "{include_prefix_path}/types.hpp"
|
|
91
|
+
|
|
92
|
+
#pragma warning(push, 0)
|
|
93
|
+
#include <nlohmann/json.hpp>
|
|
94
|
+
|
|
95
|
+
#include <memory>
|
|
96
|
+
#include <string>
|
|
97
|
+
#include <utility>
|
|
98
|
+
#pragma warning(pop)"""
|
|
99
|
+
),
|
|
100
|
+
cpp_common.generate_namespace_opening(library_namespace),
|
|
101
|
+
Stripped(
|
|
102
|
+
f"""\
|
|
103
|
+
/**
|
|
104
|
+
* \\defgroup jsonization De/serialize instances from and to JSON.
|
|
105
|
+
* @{{
|
|
106
|
+
*/
|
|
107
|
+
namespace {cpp_common.JSONIZATION_NAMESPACE} {{"""
|
|
108
|
+
),
|
|
109
|
+
Stripped(
|
|
110
|
+
f"""\
|
|
111
|
+
/**
|
|
112
|
+
* Represent a segment of a JSON path to some value.
|
|
113
|
+
*/
|
|
114
|
+
class ISegment {{
|
|
115
|
+
public:
|
|
116
|
+
{I}/**
|
|
117
|
+
{I} * \\brief Convert the segment to a string in a JSON path.
|
|
118
|
+
{I} */
|
|
119
|
+
{I}virtual std::wstring ToWstring() const = 0;
|
|
120
|
+
|
|
121
|
+
{I}virtual std::unique_ptr<ISegment> Clone() const = 0;
|
|
122
|
+
|
|
123
|
+
{I}virtual ~ISegment() = default;
|
|
124
|
+
}}; // class ISegment"""
|
|
125
|
+
),
|
|
126
|
+
Stripped(
|
|
127
|
+
f"""\
|
|
128
|
+
/**
|
|
129
|
+
* Represent a property access on a JSON path.
|
|
130
|
+
*/
|
|
131
|
+
struct PropertySegment : public ISegment {{
|
|
132
|
+
{I}/**
|
|
133
|
+
{I} * Name of the property in a JSON object
|
|
134
|
+
{I} */
|
|
135
|
+
{I}std::wstring name;
|
|
136
|
+
|
|
137
|
+
{I}PropertySegment(
|
|
138
|
+
{II}std::wstring a_name
|
|
139
|
+
{I});
|
|
140
|
+
|
|
141
|
+
{I}std::wstring ToWstring() const override;
|
|
142
|
+
|
|
143
|
+
{I}std::unique_ptr<ISegment> Clone() const override;
|
|
144
|
+
|
|
145
|
+
{I}~PropertySegment() override = default;
|
|
146
|
+
}}; // struct PropertySegment"""
|
|
147
|
+
),
|
|
148
|
+
Stripped(
|
|
149
|
+
f"""\
|
|
150
|
+
/**
|
|
151
|
+
* Represent an index access on a JSON path.
|
|
152
|
+
*/
|
|
153
|
+
struct IndexSegment : public ISegment {{
|
|
154
|
+
{I}/**
|
|
155
|
+
{I} * Index of the value in an array.
|
|
156
|
+
{I} */
|
|
157
|
+
{I}size_t index;
|
|
158
|
+
|
|
159
|
+
{I}explicit IndexSegment(
|
|
160
|
+
{II}size_t an_index
|
|
161
|
+
{I});
|
|
162
|
+
|
|
163
|
+
{I}std::wstring ToWstring() const override;
|
|
164
|
+
|
|
165
|
+
{I}std::unique_ptr<ISegment> Clone() const override;
|
|
166
|
+
|
|
167
|
+
{I}~IndexSegment() override = default;
|
|
168
|
+
}}; // struct IndexSegment"""
|
|
169
|
+
),
|
|
170
|
+
Stripped(
|
|
171
|
+
f"""\
|
|
172
|
+
/**
|
|
173
|
+
* Represent a JSON path to some value.
|
|
174
|
+
*/
|
|
175
|
+
struct Path {{
|
|
176
|
+
{I}std::deque<std::unique_ptr<ISegment> > segments;
|
|
177
|
+
|
|
178
|
+
{I}Path();
|
|
179
|
+
{I}Path(const Path& other);
|
|
180
|
+
{I}Path(Path&& other);
|
|
181
|
+
{I}Path& operator=(const Path& other);
|
|
182
|
+
{I}Path& operator=(Path&& other);
|
|
183
|
+
|
|
184
|
+
{I}std::wstring ToWstring() const;
|
|
185
|
+
}}; // struct Path"""
|
|
186
|
+
),
|
|
187
|
+
Stripped("// region De-serialization"),
|
|
188
|
+
Stripped(
|
|
189
|
+
f"""\
|
|
190
|
+
/**
|
|
191
|
+
* Represent a de-serialization error.
|
|
192
|
+
*/
|
|
193
|
+
struct DeserializationError {{
|
|
194
|
+
{I}/**
|
|
195
|
+
{I} * Human-readable description of the error
|
|
196
|
+
{I} */
|
|
197
|
+
{I}std::wstring cause;
|
|
198
|
+
|
|
199
|
+
{I}/**
|
|
200
|
+
{I} * Path to the erroneous value
|
|
201
|
+
{I} */
|
|
202
|
+
{I}Path path;
|
|
203
|
+
|
|
204
|
+
{I}explicit DeserializationError(std::wstring a_cause);
|
|
205
|
+
{I}DeserializationError(std::wstring a_cause, Path a_path);
|
|
206
|
+
}}; // struct DeserializationError"""
|
|
207
|
+
),
|
|
208
|
+
*_generate_deserialization_definitions(symbol_table=symbol_table),
|
|
209
|
+
Stripped("// endregion Deserialization"),
|
|
210
|
+
Stripped("// region Serialization"),
|
|
211
|
+
Stripped(
|
|
212
|
+
f"""\
|
|
213
|
+
/**
|
|
214
|
+
* Represent an error in the serialization of an instance to JSON.
|
|
215
|
+
*/
|
|
216
|
+
class SerializationException : public std::exception {{
|
|
217
|
+
public:
|
|
218
|
+
{I}SerializationException(
|
|
219
|
+
{II}std::wstring cause,
|
|
220
|
+
{II}iteration::Path path
|
|
221
|
+
{I});
|
|
222
|
+
|
|
223
|
+
{I}const char* what() const noexcept override;
|
|
224
|
+
|
|
225
|
+
{I}const std::wstring& cause() const noexcept;
|
|
226
|
+
{I}const iteration::Path& path() const noexcept;
|
|
227
|
+
|
|
228
|
+
{I}~SerializationException() noexcept override = default;
|
|
229
|
+
|
|
230
|
+
private:
|
|
231
|
+
{I}const std::wstring cause_;
|
|
232
|
+
{I}const iteration::Path path_;
|
|
233
|
+
{I}const std::string msg_;
|
|
234
|
+
}}; // class SerializationException"""
|
|
235
|
+
),
|
|
236
|
+
Stripped(
|
|
237
|
+
f"""\
|
|
238
|
+
/**
|
|
239
|
+
* \\brief Serialize \\p that instance to a JSON value.
|
|
240
|
+
*
|
|
241
|
+
* \\param that instance to be serialized
|
|
242
|
+
* \\return The corresponding JSON value
|
|
243
|
+
* \\throw \\ref SerializationException if a value within \\p that instance
|
|
244
|
+
* could not be serialized
|
|
245
|
+
*/
|
|
246
|
+
nlohmann::json Serialize(
|
|
247
|
+
{I}const types::IClass& that
|
|
248
|
+
);"""
|
|
249
|
+
),
|
|
250
|
+
Stripped("// endregion Serialization"),
|
|
251
|
+
Stripped(
|
|
252
|
+
f"""\
|
|
253
|
+
}} // namespace {cpp_common.JSONIZATION_NAMESPACE}
|
|
254
|
+
/**@}}*/"""
|
|
255
|
+
),
|
|
256
|
+
cpp_common.generate_namespace_closing(library_namespace),
|
|
257
|
+
cpp_common.WARNING,
|
|
258
|
+
Stripped(f"#endif // {include_guard_var}"),
|
|
259
|
+
]
|
|
260
|
+
|
|
261
|
+
writer = io.StringIO()
|
|
262
|
+
for i, block in enumerate(blocks):
|
|
263
|
+
if i > 0:
|
|
264
|
+
writer.write("\n\n")
|
|
265
|
+
|
|
266
|
+
writer.write(block)
|
|
267
|
+
|
|
268
|
+
writer.write("\n")
|
|
269
|
+
|
|
270
|
+
return writer.getvalue()
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def _generate_property_segment_implementation() -> List[Stripped]:
|
|
274
|
+
"""Generate the implementation of the struct ``PropertySegment``."""
|
|
275
|
+
return [
|
|
276
|
+
Stripped("// region PropertySegment"),
|
|
277
|
+
Stripped(
|
|
278
|
+
f"""\
|
|
279
|
+
PropertySegment::PropertySegment(
|
|
280
|
+
{I}std::wstring a_name
|
|
281
|
+
) :
|
|
282
|
+
{I}name(std::move(a_name)) {{
|
|
283
|
+
{I}// Intentionally empty.
|
|
284
|
+
}}"""
|
|
285
|
+
),
|
|
286
|
+
Stripped(
|
|
287
|
+
f"""\
|
|
288
|
+
std::wstring PropertySegment::ToWstring() const {{
|
|
289
|
+
{I}return common::Concat(
|
|
290
|
+
{II}L".",
|
|
291
|
+
{II}name
|
|
292
|
+
{I});
|
|
293
|
+
}}"""
|
|
294
|
+
),
|
|
295
|
+
Stripped(
|
|
296
|
+
f"""\
|
|
297
|
+
std::unique_ptr<ISegment> PropertySegment::Clone() const {{
|
|
298
|
+
{I}return common::make_unique<PropertySegment>(*this);
|
|
299
|
+
}}"""
|
|
300
|
+
),
|
|
301
|
+
Stripped("// endregion PropertySegment"),
|
|
302
|
+
]
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def _generate_index_segment_implementation() -> List[Stripped]:
|
|
306
|
+
"""Generate the implementation of the struct ``IndexSegment``."""
|
|
307
|
+
return [
|
|
308
|
+
Stripped("// region IndexSegment"),
|
|
309
|
+
Stripped(
|
|
310
|
+
f"""\
|
|
311
|
+
IndexSegment::IndexSegment(
|
|
312
|
+
{I}size_t an_index
|
|
313
|
+
) :
|
|
314
|
+
{I}index(an_index) {{
|
|
315
|
+
{I}// Intentionally empty.
|
|
316
|
+
}}"""
|
|
317
|
+
),
|
|
318
|
+
Stripped(
|
|
319
|
+
f"""\
|
|
320
|
+
std::wstring IndexSegment::ToWstring() const {{
|
|
321
|
+
{I}return common::Concat(
|
|
322
|
+
{II}L"[",
|
|
323
|
+
{II}std::to_wstring(index),
|
|
324
|
+
{II}L"]"
|
|
325
|
+
{I});
|
|
326
|
+
}}"""
|
|
327
|
+
),
|
|
328
|
+
Stripped(
|
|
329
|
+
f"""\
|
|
330
|
+
std::unique_ptr<ISegment> IndexSegment::Clone() const {{
|
|
331
|
+
{I}return common::make_unique<IndexSegment>(*this);
|
|
332
|
+
}}"""
|
|
333
|
+
),
|
|
334
|
+
Stripped("// endregion IndexSegment"),
|
|
335
|
+
]
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def _generate_path_implementation() -> List[Stripped]:
|
|
339
|
+
"""Generate the implementation of the struct ``Path``."""
|
|
340
|
+
return [
|
|
341
|
+
Stripped("// region struct Path"),
|
|
342
|
+
Stripped(
|
|
343
|
+
f"""\
|
|
344
|
+
Path::Path() {{
|
|
345
|
+
{I}// Intentionally empty.
|
|
346
|
+
}}"""
|
|
347
|
+
),
|
|
348
|
+
Stripped(
|
|
349
|
+
f"""\
|
|
350
|
+
Path::Path(const Path& other) {{
|
|
351
|
+
{I}for (const std::unique_ptr<ISegment>& segment : other.segments) {{
|
|
352
|
+
{II}segments.emplace_back(segment->Clone());
|
|
353
|
+
{I}}}
|
|
354
|
+
}}"""
|
|
355
|
+
),
|
|
356
|
+
Stripped(
|
|
357
|
+
f"""\
|
|
358
|
+
Path::Path(Path&& other) {{
|
|
359
|
+
{I}segments = std::move(other.segments);
|
|
360
|
+
}}"""
|
|
361
|
+
),
|
|
362
|
+
Stripped(
|
|
363
|
+
f"""\
|
|
364
|
+
Path& Path::operator=(const Path& other) {{
|
|
365
|
+
{I}segments.clear();
|
|
366
|
+
{I}for (const std::unique_ptr<ISegment>& segment : other.segments) {{
|
|
367
|
+
{II}segments.emplace_back(segment->Clone());
|
|
368
|
+
{I}}}
|
|
369
|
+
{I}return *this;
|
|
370
|
+
}}"""
|
|
371
|
+
),
|
|
372
|
+
Stripped(
|
|
373
|
+
f"""\
|
|
374
|
+
Path& Path::operator=(Path&& other) {{
|
|
375
|
+
{I}if (this != &other) {{
|
|
376
|
+
{II}segments = std::move(other.segments);
|
|
377
|
+
{I}}}
|
|
378
|
+
{I}return *this;
|
|
379
|
+
}}"""
|
|
380
|
+
),
|
|
381
|
+
Stripped(
|
|
382
|
+
f"""\
|
|
383
|
+
std::wstring Path::ToWstring() const {{
|
|
384
|
+
{I}if (segments.empty()) {{
|
|
385
|
+
{II}return L"";
|
|
386
|
+
{I}}}
|
|
387
|
+
|
|
388
|
+
{I}std::deque<std::wstring> parts;
|
|
389
|
+
{I}for (const std::unique_ptr<ISegment>& segment : segments ) {{
|
|
390
|
+
{II}parts.emplace_back(segment->ToWstring());
|
|
391
|
+
{I}}}
|
|
392
|
+
|
|
393
|
+
{I}size_t out_len = 0;
|
|
394
|
+
{I}for (const std::wstring& part : parts) {{
|
|
395
|
+
{II}out_len += part.size();
|
|
396
|
+
{I}}}
|
|
397
|
+
|
|
398
|
+
{I}std::wstring out;
|
|
399
|
+
{I}out.reserve(out_len);
|
|
400
|
+
{I}for (const std::wstring& part : parts) {{
|
|
401
|
+
{II}out.append(part);
|
|
402
|
+
{I}}}
|
|
403
|
+
|
|
404
|
+
{I}return out;
|
|
405
|
+
}}"""
|
|
406
|
+
),
|
|
407
|
+
Stripped("// endregion struct Path"),
|
|
408
|
+
]
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def _generate_deserialization_error_implementation() -> List[Stripped]:
|
|
412
|
+
"""Generate the impl. of the deserialization error class."""
|
|
413
|
+
return [
|
|
414
|
+
Stripped("// region class DeserializationError"),
|
|
415
|
+
Stripped(
|
|
416
|
+
f"""\
|
|
417
|
+
DeserializationError::DeserializationError(
|
|
418
|
+
{I}std::wstring a_cause
|
|
419
|
+
) :
|
|
420
|
+
{I}cause(a_cause) {{
|
|
421
|
+
{I}// Intentionally empty.
|
|
422
|
+
}}"""
|
|
423
|
+
),
|
|
424
|
+
Stripped(
|
|
425
|
+
f"""\
|
|
426
|
+
DeserializationError::DeserializationError(
|
|
427
|
+
{I}std::wstring a_cause,
|
|
428
|
+
{I}Path a_path
|
|
429
|
+
) :
|
|
430
|
+
{I}cause(a_cause),
|
|
431
|
+
{I}path(a_path) {{
|
|
432
|
+
{I}// Intentionally empty.
|
|
433
|
+
}}"""
|
|
434
|
+
),
|
|
435
|
+
Stripped("// endregion class DeserializationError"),
|
|
436
|
+
]
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
def _generate_deserialize_bool() -> Stripped:
|
|
440
|
+
"""Generate the function to de-serialize a boolean from a JSON value."""
|
|
441
|
+
return Stripped(
|
|
442
|
+
f"""\
|
|
443
|
+
std::pair<
|
|
444
|
+
{I}common::optional<bool>,
|
|
445
|
+
{I}common::optional<DeserializationError>
|
|
446
|
+
> DeserializeBool(
|
|
447
|
+
{I}const nlohmann::json& json
|
|
448
|
+
) {{
|
|
449
|
+
{I}if (!json.is_boolean()) {{
|
|
450
|
+
{II}std::wstring message = common::Concat(
|
|
451
|
+
{III}L"Expected a boolean, but got a value of type: ",
|
|
452
|
+
{III}common::Utf8ToWstring(json.type_name())
|
|
453
|
+
{II});
|
|
454
|
+
|
|
455
|
+
{II}return std::make_pair<
|
|
456
|
+
{III}common::optional<bool>,
|
|
457
|
+
{III}common::optional<DeserializationError>
|
|
458
|
+
{II}>(
|
|
459
|
+
{III}common::nullopt,
|
|
460
|
+
{III}common::make_optional<DeserializationError>(
|
|
461
|
+
{IIII}message
|
|
462
|
+
{III})
|
|
463
|
+
{II});
|
|
464
|
+
{I}}}
|
|
465
|
+
|
|
466
|
+
{I}return std::make_pair<
|
|
467
|
+
{II}common::optional<bool>,
|
|
468
|
+
{II}common::optional<DeserializationError>
|
|
469
|
+
{I}>(
|
|
470
|
+
{II}json.get<bool>(),
|
|
471
|
+
{II}common::nullopt
|
|
472
|
+
{I});
|
|
473
|
+
}}"""
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
def _generate_deserialize_int() -> Stripped:
|
|
478
|
+
"""Generate the function to de-serialize an int from a JSON value."""
|
|
479
|
+
return Stripped(
|
|
480
|
+
f"""\
|
|
481
|
+
std::pair<
|
|
482
|
+
{I}common::optional<int64_t>,
|
|
483
|
+
{I}common::optional<DeserializationError>
|
|
484
|
+
> DeserializeInt64(
|
|
485
|
+
{I}const nlohmann::json& json
|
|
486
|
+
) {{
|
|
487
|
+
{I}if (!json.is_number()) {{
|
|
488
|
+
{II}std::wstring message = common::Concat(
|
|
489
|
+
{III}L"Expected an integer number, but got a value of type: ",
|
|
490
|
+
{III}common::Utf8ToWstring(json.type_name())
|
|
491
|
+
{II});
|
|
492
|
+
|
|
493
|
+
{II}return std::make_pair<
|
|
494
|
+
{III}common::optional<int64_t>,
|
|
495
|
+
{III}common::optional<DeserializationError>
|
|
496
|
+
{II}>(
|
|
497
|
+
{III}common::nullopt,
|
|
498
|
+
{III}common::make_optional<DeserializationError>(
|
|
499
|
+
{IIII}message
|
|
500
|
+
{III})
|
|
501
|
+
{II});
|
|
502
|
+
{I}}}
|
|
503
|
+
|
|
504
|
+
{I}static_assert(
|
|
505
|
+
{II}std::is_same<nlohmann::json::number_integer_t, int64_t>::value,
|
|
506
|
+
{II}"Expected nlohmann::json::number_integer_t to equal int64_t, "
|
|
507
|
+
{II}"but it does not."
|
|
508
|
+
{I});
|
|
509
|
+
|
|
510
|
+
{I}if (json.is_number_integer()) {{
|
|
511
|
+
{II}return std::make_pair<
|
|
512
|
+
{III}common::optional<int64_t>,
|
|
513
|
+
{III}common::optional<DeserializationError>
|
|
514
|
+
{II}>(
|
|
515
|
+
{III}json.get<int64_t>(),
|
|
516
|
+
{III}common::nullopt
|
|
517
|
+
{II});
|
|
518
|
+
{I}}}
|
|
519
|
+
|
|
520
|
+
{I}if (json.is_number_unsigned()) {{
|
|
521
|
+
{II}std::wstring message = common::Concat(
|
|
522
|
+
{III}L"Expected a 64-bit integer number, "
|
|
523
|
+
{III}L"but got an unsigned integer number which does not fit in that range: ",
|
|
524
|
+
{III}std::to_wstring(json.get<nlohmann::json::number_unsigned_t>())
|
|
525
|
+
{II});
|
|
526
|
+
|
|
527
|
+
{II}return std::make_pair<
|
|
528
|
+
{III}common::optional<int64_t>,
|
|
529
|
+
{III}common::optional<DeserializationError>
|
|
530
|
+
{II}>(
|
|
531
|
+
{III}common::nullopt,
|
|
532
|
+
{III}common::make_optional<DeserializationError>(
|
|
533
|
+
{IIII}message
|
|
534
|
+
{III})
|
|
535
|
+
{II});
|
|
536
|
+
{I}}}
|
|
537
|
+
|
|
538
|
+
{I}// NOTE (mristin):
|
|
539
|
+
{I}// We have to check that the number is an integer even though it can
|
|
540
|
+
{I}// not be stored in int64_t in order to give an informative message.
|
|
541
|
+
|
|
542
|
+
{I}const nlohmann::json::number_float_t number(
|
|
543
|
+
{II}json.get<nlohmann::json::number_float_t>()
|
|
544
|
+
{I});
|
|
545
|
+
|
|
546
|
+
{I}nlohmann::json::number_float_t integer_part;
|
|
547
|
+
{I}const bool is_integer(
|
|
548
|
+
{II}std::modf(number, &integer_part) == 0
|
|
549
|
+
{I});
|
|
550
|
+
{I}if (is_integer) {{
|
|
551
|
+
{II}std::wstring message = common::Concat(
|
|
552
|
+
{III}L"Expected a 64-bit integer number, "
|
|
553
|
+
{III}L"but got an integer number which does not fit in that range: ",
|
|
554
|
+
{III}std::to_wstring(number)
|
|
555
|
+
{II});
|
|
556
|
+
|
|
557
|
+
{II}return std::make_pair<
|
|
558
|
+
{III}common::optional<int64_t>,
|
|
559
|
+
{III}common::optional<DeserializationError>
|
|
560
|
+
{II}>(
|
|
561
|
+
{III}common::nullopt,
|
|
562
|
+
{III}common::make_optional<DeserializationError>(
|
|
563
|
+
{IIII}message
|
|
564
|
+
{III})
|
|
565
|
+
{II});
|
|
566
|
+
{I}}} else {{
|
|
567
|
+
{II}std::wstring message = common::Concat(
|
|
568
|
+
{III}L"Expected a 64-bit integer number, "
|
|
569
|
+
{III}L"but got a non-integer number: ",
|
|
570
|
+
{III}std::to_wstring(number)
|
|
571
|
+
{II});
|
|
572
|
+
|
|
573
|
+
{II}return std::make_pair<
|
|
574
|
+
{III}common::optional<int64_t>,
|
|
575
|
+
{III}common::optional<DeserializationError>
|
|
576
|
+
{II}>(
|
|
577
|
+
{III}common::nullopt,
|
|
578
|
+
{III}common::make_optional<DeserializationError>(
|
|
579
|
+
{IIII}message
|
|
580
|
+
{III})
|
|
581
|
+
{II});
|
|
582
|
+
{I}}}
|
|
583
|
+
}}"""
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
def _generate_deserialize_float() -> Stripped:
|
|
588
|
+
"""Generate the function to de-serialize a float from a JSON value."""
|
|
589
|
+
return Stripped(
|
|
590
|
+
f"""\
|
|
591
|
+
std::pair<
|
|
592
|
+
{I}common::optional<double>,
|
|
593
|
+
{I}common::optional<DeserializationError>
|
|
594
|
+
> DeserializeDouble(
|
|
595
|
+
{I}const nlohmann::json& json
|
|
596
|
+
) {{
|
|
597
|
+
{I}if (!json.is_number()) {{
|
|
598
|
+
{II}std::wstring message = common::Concat(
|
|
599
|
+
{III}L"Expected a number, but got a value of type: ",
|
|
600
|
+
{III}common::Utf8ToWstring(json.type_name())
|
|
601
|
+
{II});
|
|
602
|
+
|
|
603
|
+
{II}return std::make_pair<
|
|
604
|
+
{III}common::optional<double>,
|
|
605
|
+
{III}common::optional<DeserializationError>
|
|
606
|
+
{II}>(
|
|
607
|
+
{III}common::nullopt,
|
|
608
|
+
{III}common::make_optional<DeserializationError>(
|
|
609
|
+
{IIII}message
|
|
610
|
+
{III})
|
|
611
|
+
{II});
|
|
612
|
+
{I}}}
|
|
613
|
+
|
|
614
|
+
{I}static_assert(
|
|
615
|
+
{II}std::is_same<nlohmann::json::number_float_t, double>::value,
|
|
616
|
+
{II}"Expected nlohmann::json::number_float_t to equal double, "
|
|
617
|
+
{II}"but it does not."
|
|
618
|
+
{I});
|
|
619
|
+
|
|
620
|
+
{I}return std::make_pair<
|
|
621
|
+
{II}common::optional<double>,
|
|
622
|
+
{II}common::optional<DeserializationError>
|
|
623
|
+
{I}>(
|
|
624
|
+
{II}json.get<double>(),
|
|
625
|
+
{II}common::nullopt
|
|
626
|
+
{I});
|
|
627
|
+
}}"""
|
|
628
|
+
)
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
def _generate_deserialize_str() -> Stripped:
|
|
632
|
+
"""Generate the function to de-serialize a string from a JSON value."""
|
|
633
|
+
return Stripped(
|
|
634
|
+
f"""\
|
|
635
|
+
std::pair<
|
|
636
|
+
{I}common::optional<std::wstring>,
|
|
637
|
+
{I}common::optional<DeserializationError>
|
|
638
|
+
> DeserializeWstring(
|
|
639
|
+
{I}const nlohmann::json& json
|
|
640
|
+
) {{
|
|
641
|
+
{I}if (!json.is_string()) {{
|
|
642
|
+
{II}std::wstring message = common::Concat(
|
|
643
|
+
{III}L"Expected a string, but got a value of type: ",
|
|
644
|
+
{III}common::Utf8ToWstring(json.type_name())
|
|
645
|
+
{II});
|
|
646
|
+
|
|
647
|
+
{II}return std::make_pair<
|
|
648
|
+
{III}common::optional<std::wstring>,
|
|
649
|
+
{III}common::optional<DeserializationError>
|
|
650
|
+
{II}>(
|
|
651
|
+
{III}common::nullopt,
|
|
652
|
+
{III}common::make_optional<DeserializationError>(
|
|
653
|
+
{IIII}message
|
|
654
|
+
{III})
|
|
655
|
+
{II});
|
|
656
|
+
{I}}}
|
|
657
|
+
|
|
658
|
+
{I}return std::make_pair<
|
|
659
|
+
{II}common::optional<std::wstring>,
|
|
660
|
+
{II}common::optional<DeserializationError>
|
|
661
|
+
{I}>(
|
|
662
|
+
{II}common::Utf8ToWstring(*(json.get_ptr<const std::string*>())),
|
|
663
|
+
{II}common::nullopt
|
|
664
|
+
{I});
|
|
665
|
+
}}"""
|
|
666
|
+
)
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
def _generate_deserialize_bytearray() -> Stripped:
|
|
670
|
+
"""Generate the function to de-serialize a bytearray from a JSON value."""
|
|
671
|
+
return Stripped(
|
|
672
|
+
f"""\
|
|
673
|
+
std::pair<
|
|
674
|
+
{I}common::optional<std::vector<std::uint8_t> >,
|
|
675
|
+
{I}common::optional<DeserializationError>
|
|
676
|
+
> DeserializeByteArray(
|
|
677
|
+
{I}const nlohmann::json& json
|
|
678
|
+
) {{
|
|
679
|
+
{I}if (!json.is_string()) {{
|
|
680
|
+
{II}std::wstring message = common::Concat(
|
|
681
|
+
{III}L"Expected a base64-encoded byte array as a string, "
|
|
682
|
+
{III}L"but got a value of type: ",
|
|
683
|
+
{III}common::Utf8ToWstring(json.type_name())
|
|
684
|
+
{II});;
|
|
685
|
+
|
|
686
|
+
{II}return std::make_pair<
|
|
687
|
+
{III}common::optional<std::vector<std::uint8_t> >,
|
|
688
|
+
{III}common::optional<DeserializationError>
|
|
689
|
+
{II}>(
|
|
690
|
+
{III}common::nullopt,
|
|
691
|
+
{III}common::make_optional<DeserializationError>(
|
|
692
|
+
{IIII}message
|
|
693
|
+
{III})
|
|
694
|
+
{II});
|
|
695
|
+
{I}}}
|
|
696
|
+
|
|
697
|
+
{I}common::expected<
|
|
698
|
+
{II}std::vector<std::uint8_t>,
|
|
699
|
+
{II}std::string
|
|
700
|
+
{I}> bytes = stringification::Base64Decode(
|
|
701
|
+
{II}*(json.get_ptr<const std::string*>())
|
|
702
|
+
{I});
|
|
703
|
+
|
|
704
|
+
{I}if (!bytes.has_value()) {{
|
|
705
|
+
{II}std::wstring message = common::Concat(
|
|
706
|
+
{III}L"Failed to base64-decode the bytes from a string: ",
|
|
707
|
+
{III}common::Utf8ToWstring(bytes.error())
|
|
708
|
+
{II});
|
|
709
|
+
|
|
710
|
+
{II}return std::make_pair<
|
|
711
|
+
{III}common::optional<std::vector<std::uint8_t> >,
|
|
712
|
+
{III}common::optional<DeserializationError>
|
|
713
|
+
{II}>(
|
|
714
|
+
{III}common::nullopt,
|
|
715
|
+
{III}common::make_optional<DeserializationError>(
|
|
716
|
+
{IIII}message
|
|
717
|
+
{III})
|
|
718
|
+
{II});
|
|
719
|
+
{I}}}
|
|
720
|
+
|
|
721
|
+
{I}return std::make_pair<
|
|
722
|
+
{II}common::optional<std::vector<std::uint8_t> >,
|
|
723
|
+
{II}common::optional<DeserializationError>
|
|
724
|
+
{I}>(
|
|
725
|
+
{II}std::move(*bytes),
|
|
726
|
+
{II}common::nullopt
|
|
727
|
+
{I});
|
|
728
|
+
}}"""
|
|
729
|
+
)
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
_PRIMITIVE_TYPE_TO_DESERIALIZE = {
|
|
733
|
+
intermediate.PrimitiveType.BOOL: "DeserializeBool",
|
|
734
|
+
intermediate.PrimitiveType.INT: "DeserializeInt64",
|
|
735
|
+
intermediate.PrimitiveType.FLOAT: "DeserializeDouble",
|
|
736
|
+
intermediate.PrimitiveType.STR: "DeserializeWstring",
|
|
737
|
+
intermediate.PrimitiveType.BYTEARRAY: "DeserializeByteArray",
|
|
738
|
+
}
|
|
739
|
+
assert all(
|
|
740
|
+
primitive_type in _PRIMITIVE_TYPE_TO_DESERIALIZE
|
|
741
|
+
for primitive_type in intermediate.PrimitiveType
|
|
742
|
+
)
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
def _generate_get_model_type() -> Stripped:
|
|
746
|
+
"""Generate the getter of the model type from JSON object for dispatches."""
|
|
747
|
+
return Stripped(
|
|
748
|
+
f"""\
|
|
749
|
+
/**
|
|
750
|
+
* Get the property `modelType` from the JSON value expected as a JSON object.
|
|
751
|
+
*/
|
|
752
|
+
std::pair<
|
|
753
|
+
{I}const std::string*,
|
|
754
|
+
{I}common::optional<DeserializationError>
|
|
755
|
+
> GetModelTypeFrom(
|
|
756
|
+
{I}const nlohmann::json& json
|
|
757
|
+
) {{
|
|
758
|
+
{I}if (!json.is_object()) {{
|
|
759
|
+
{II}std::wstring message = common::Concat(
|
|
760
|
+
{III}L"Expected an object, but got: ",
|
|
761
|
+
{III}common::Utf8ToWstring(json.type_name())
|
|
762
|
+
{II});
|
|
763
|
+
|
|
764
|
+
{II}return std::make_pair<
|
|
765
|
+
{III}const std::string*,
|
|
766
|
+
{III}common::optional<DeserializationError>
|
|
767
|
+
{II}>(
|
|
768
|
+
{III}nullptr,
|
|
769
|
+
{III}common::make_optional<DeserializationError>(
|
|
770
|
+
{IIII}message
|
|
771
|
+
{III})
|
|
772
|
+
{II});
|
|
773
|
+
{I}}}
|
|
774
|
+
|
|
775
|
+
{I}if (!json.contains("modelType")) {{
|
|
776
|
+
{II}return std::make_pair<
|
|
777
|
+
{III}const std::string*,
|
|
778
|
+
{III}common::optional<DeserializationError>
|
|
779
|
+
{II}>(
|
|
780
|
+
{III}nullptr,
|
|
781
|
+
{III}common::make_optional<DeserializationError>(
|
|
782
|
+
{IIII}L"The required property modelType is missing"
|
|
783
|
+
{III})
|
|
784
|
+
{II});
|
|
785
|
+
{I}}}
|
|
786
|
+
|
|
787
|
+
{I}const nlohmann::json& model_type_prop = json["modelType"];
|
|
788
|
+
{I}if (!model_type_prop.is_string()) {{
|
|
789
|
+
{II}std::wstring message = common::Concat(
|
|
790
|
+
{III}L"Expected modelType to be a string, but got: ",
|
|
791
|
+
{III}common::Utf8ToWstring(model_type_prop.type_name())
|
|
792
|
+
{II});
|
|
793
|
+
|
|
794
|
+
{II}common::optional<DeserializationError> error(
|
|
795
|
+
{III}common::make_optional<DeserializationError>(
|
|
796
|
+
{IIII}message
|
|
797
|
+
{III})
|
|
798
|
+
{II});
|
|
799
|
+
{II}error->path.segments.emplace_front(
|
|
800
|
+
{III}common::make_unique<PropertySegment>(
|
|
801
|
+
{IIII}L"modelType"
|
|
802
|
+
{III})
|
|
803
|
+
{II});
|
|
804
|
+
|
|
805
|
+
{II}// NOTE (mristin):
|
|
806
|
+
{II}// We have to explicitly use the constructor instead of std::make_pair
|
|
807
|
+
{II}// as `const std::string*` can not be automatically converted to a rvalue.
|
|
808
|
+
{II}return std::pair<
|
|
809
|
+
{III}const std::string*,
|
|
810
|
+
{III}common::optional<DeserializationError>
|
|
811
|
+
{II}>(
|
|
812
|
+
{III}nullptr,
|
|
813
|
+
{III}error
|
|
814
|
+
{II});
|
|
815
|
+
{I}}}
|
|
816
|
+
|
|
817
|
+
{I}static_assert(
|
|
818
|
+
{II}std::is_same<nlohmann::json::string_t, std::string>::value,
|
|
819
|
+
{II}"Expected nlohmann::json::string_t to equal std::string, but it does not."
|
|
820
|
+
{I});
|
|
821
|
+
|
|
822
|
+
{I}const std::string* model_type(
|
|
823
|
+
{II}model_type_prop.get_ptr<const std::string*>()
|
|
824
|
+
{I});
|
|
825
|
+
|
|
826
|
+
{I}// NOTE (mristin):
|
|
827
|
+
{I}// We have to explicitly use the constructor instead of std::make_pair
|
|
828
|
+
{I}// as `const std::string*` can not be automatically converted to a rvalue.
|
|
829
|
+
{I}return std::pair<
|
|
830
|
+
{II}const std::string*,
|
|
831
|
+
{II}common::optional<DeserializationError>
|
|
832
|
+
{I}>(
|
|
833
|
+
{II}model_type,
|
|
834
|
+
{II}common::nullopt
|
|
835
|
+
{I});
|
|
836
|
+
}}"""
|
|
837
|
+
)
|
|
838
|
+
|
|
839
|
+
|
|
840
|
+
def _generate_concretely_deserialize_definition(
|
|
841
|
+
cls: intermediate.ClassUnion,
|
|
842
|
+
) -> Stripped:
|
|
843
|
+
"""Generate the definition of the concrete ``Deserialize*`` functions."""
|
|
844
|
+
interface_name = cpp_naming.interface_name(cls.name)
|
|
845
|
+
|
|
846
|
+
if len(cls.concrete_descendants) == 0:
|
|
847
|
+
function_name = cpp_naming.function_name(Identifier(f"deserialize_{cls.name}"))
|
|
848
|
+
else:
|
|
849
|
+
function_name = cpp_naming.function_name(
|
|
850
|
+
Identifier(f"concretely_deserialize_{cls.name}")
|
|
851
|
+
)
|
|
852
|
+
|
|
853
|
+
if len(cls.ancestors) > 0:
|
|
854
|
+
# NOTE (mristin, 2023-11-10):
|
|
855
|
+
# We have to introduce the template so that we do not have to
|
|
856
|
+
# unnecessarily upcast the instance to ancestor classes.
|
|
857
|
+
prefix = Stripped(
|
|
858
|
+
f"""\
|
|
859
|
+
template <
|
|
860
|
+
{I}typename T,
|
|
861
|
+
{I}typename std::enable_if<
|
|
862
|
+
{II}std::is_base_of<T, types::{interface_name}>::value
|
|
863
|
+
{I}>::type* = nullptr
|
|
864
|
+
>
|
|
865
|
+
std::pair<
|
|
866
|
+
{I}common::optional<std::shared_ptr<T> >,
|
|
867
|
+
{I}common::optional<DeserializationError>
|
|
868
|
+
>"""
|
|
869
|
+
)
|
|
870
|
+
else:
|
|
871
|
+
prefix = Stripped(
|
|
872
|
+
f"""\
|
|
873
|
+
std::pair<
|
|
874
|
+
{I}common::optional<
|
|
875
|
+
{II}std::shared_ptr<types::{interface_name}>
|
|
876
|
+
{I}>,
|
|
877
|
+
{I}common::optional<DeserializationError>
|
|
878
|
+
>"""
|
|
879
|
+
)
|
|
880
|
+
|
|
881
|
+
return Stripped(
|
|
882
|
+
f"""\
|
|
883
|
+
/**
|
|
884
|
+
* \\brief Deserialize concretely an instance
|
|
885
|
+
* of types::{interface_name}.
|
|
886
|
+
*
|
|
887
|
+
* \\param json value to be de-serialized
|
|
888
|
+
* \\param additional_properties if not set, check that \\p json contains
|
|
889
|
+
* no additional properties
|
|
890
|
+
* \\return the deserialized instance, or an error, if any
|
|
891
|
+
*/
|
|
892
|
+
{prefix} {function_name}(
|
|
893
|
+
{I}const nlohmann::json& json,
|
|
894
|
+
{I}bool additional_properties
|
|
895
|
+
);"""
|
|
896
|
+
)
|
|
897
|
+
|
|
898
|
+
|
|
899
|
+
@require(
|
|
900
|
+
lambda cls: len(cls.concrete_descendants) > 0,
|
|
901
|
+
"No dispatch possible without concrete descendants",
|
|
902
|
+
)
|
|
903
|
+
def _generate_dispatch_deserialize_definition(cls: intermediate.ClassUnion) -> Stripped:
|
|
904
|
+
"""Generate the def. of the dispatching deserialization function for ``cls``."""
|
|
905
|
+
interface_name = cpp_naming.interface_name(cls.name)
|
|
906
|
+
|
|
907
|
+
function_name = cpp_naming.function_name(Identifier(f"deserialize_{cls.name}"))
|
|
908
|
+
|
|
909
|
+
return Stripped(
|
|
910
|
+
f"""\
|
|
911
|
+
/**
|
|
912
|
+
* \\brief Dispatch the deserialization for an instance
|
|
913
|
+
* of types::{interface_name}.
|
|
914
|
+
*
|
|
915
|
+
* \\param json value to be de-serialized
|
|
916
|
+
* \\param additional_properties if not set, check that \\p json contains
|
|
917
|
+
* no additional properties
|
|
918
|
+
* \\return the deserialized instance, or an error, if any
|
|
919
|
+
*/
|
|
920
|
+
std::pair<
|
|
921
|
+
{I}common::optional<
|
|
922
|
+
{II}std::shared_ptr<types::{interface_name}>
|
|
923
|
+
{I}>,
|
|
924
|
+
{I}common::optional<DeserializationError>
|
|
925
|
+
> {function_name}(
|
|
926
|
+
{I}const nlohmann::json& json,
|
|
927
|
+
{I}bool additional_properties
|
|
928
|
+
);"""
|
|
929
|
+
)
|
|
930
|
+
|
|
931
|
+
|
|
932
|
+
def _generate_deserialize_primitive_property(
|
|
933
|
+
prop: intermediate.Property, ok_type: Stripped
|
|
934
|
+
) -> Stripped:
|
|
935
|
+
"""
|
|
936
|
+
Generate the snippet to de-serialize the primitive property.
|
|
937
|
+
|
|
938
|
+
We assume that the check whether the property is set is performed elsewhere.
|
|
939
|
+
|
|
940
|
+
The ``ok_type`` denotes the type of the deserialized instance, *not* the property.
|
|
941
|
+
We have to distinguish between cases where we directly create an upcast pointer to
|
|
942
|
+
an ancestor class, and cases where there are no ancestor classes.
|
|
943
|
+
"""
|
|
944
|
+
type_anno = intermediate.beneath_optional(prop.type_annotation)
|
|
945
|
+
primitive_type = intermediate.try_primitive_type(type_anno)
|
|
946
|
+
|
|
947
|
+
assert (
|
|
948
|
+
primitive_type is not None
|
|
949
|
+
), f"Primitive property expected, got for {prop.name!r}: {prop.type_annotation}"
|
|
950
|
+
|
|
951
|
+
deserialize_primitive = _PRIMITIVE_TYPE_TO_DESERIALIZE[primitive_type]
|
|
952
|
+
|
|
953
|
+
json_prop_name = naming.json_property(prop.name)
|
|
954
|
+
|
|
955
|
+
var_name = cpp_naming.variable_name(Identifier(f"the_{prop.name}"))
|
|
956
|
+
|
|
957
|
+
return Stripped(
|
|
958
|
+
f"""\
|
|
959
|
+
std::tie(
|
|
960
|
+
{I}{var_name},
|
|
961
|
+
{I}error
|
|
962
|
+
) = {deserialize_primitive}(
|
|
963
|
+
{I}json[{cpp_common.string_literal(json_prop_name)}]
|
|
964
|
+
);
|
|
965
|
+
|
|
966
|
+
if (error.has_value()) {{
|
|
967
|
+
{I}error->path.segments.emplace_front(
|
|
968
|
+
{II}common::make_unique<PropertySegment>(
|
|
969
|
+
{III}{cpp_common.wstring_literal(json_prop_name)}
|
|
970
|
+
{II})
|
|
971
|
+
{I});
|
|
972
|
+
|
|
973
|
+
{I}return std::make_pair<
|
|
974
|
+
{II}common::optional<std::shared_ptr<{ok_type}> >,
|
|
975
|
+
{II}common::optional<DeserializationError>
|
|
976
|
+
{I}>(
|
|
977
|
+
{II}common::nullopt,
|
|
978
|
+
{II}std::move(error)
|
|
979
|
+
{I});
|
|
980
|
+
}}"""
|
|
981
|
+
)
|
|
982
|
+
|
|
983
|
+
|
|
984
|
+
def _generate_deserialize_enumeration_property(
|
|
985
|
+
prop: intermediate.Property, ok_type: Stripped
|
|
986
|
+
) -> Stripped:
|
|
987
|
+
"""
|
|
988
|
+
Generate the snippet to de-serialize the enumeration property.
|
|
989
|
+
|
|
990
|
+
We assume that the check whether the property is set is performed elsewhere.
|
|
991
|
+
|
|
992
|
+
The ``ok_type`` denotes the type of the deserialized instance, *not* the property.
|
|
993
|
+
We have to distinguish between cases where we directly create an upcast pointer to
|
|
994
|
+
an ancestor class, and cases where there are no ancestor classes.
|
|
995
|
+
"""
|
|
996
|
+
type_anno = intermediate.beneath_optional(prop.type_annotation)
|
|
997
|
+
assert isinstance(type_anno, intermediate.OurTypeAnnotation) and isinstance(
|
|
998
|
+
type_anno.our_type, intermediate.Enumeration
|
|
999
|
+
)
|
|
1000
|
+
|
|
1001
|
+
enum = type_anno.our_type
|
|
1002
|
+
enum_name = cpp_naming.enum_name(enum.name)
|
|
1003
|
+
|
|
1004
|
+
from_wstring = cpp_naming.function_name(Identifier(f"{enum.name}_from_wstring"))
|
|
1005
|
+
|
|
1006
|
+
json_prop_name = naming.json_property(prop.name)
|
|
1007
|
+
|
|
1008
|
+
var_name = cpp_naming.variable_name(Identifier(f"the_{prop.name}"))
|
|
1009
|
+
var_text_name = cpp_naming.variable_name(Identifier(f"text_{prop.name}"))
|
|
1010
|
+
|
|
1011
|
+
return Stripped(
|
|
1012
|
+
f"""\
|
|
1013
|
+
common::optional<std::wstring> {var_text_name};
|
|
1014
|
+
|
|
1015
|
+
std::tie(
|
|
1016
|
+
{I}{var_text_name},
|
|
1017
|
+
{I}error
|
|
1018
|
+
) = DeserializeWstring(
|
|
1019
|
+
{I}json[{cpp_common.string_literal(json_prop_name)}]
|
|
1020
|
+
);
|
|
1021
|
+
|
|
1022
|
+
if (error.has_value()) {{
|
|
1023
|
+
{I}error->path.segments.emplace_front(
|
|
1024
|
+
{II}common::make_unique<PropertySegment>(
|
|
1025
|
+
{III}{cpp_common.wstring_literal(json_prop_name)}
|
|
1026
|
+
{II})
|
|
1027
|
+
{I});
|
|
1028
|
+
|
|
1029
|
+
{I}return std::make_pair<
|
|
1030
|
+
{II}common::optional<std::shared_ptr<{ok_type}> >,
|
|
1031
|
+
{II}common::optional<DeserializationError>
|
|
1032
|
+
{I}>(
|
|
1033
|
+
{II}common::nullopt,
|
|
1034
|
+
{II}std::move(error)
|
|
1035
|
+
{I});
|
|
1036
|
+
}}
|
|
1037
|
+
|
|
1038
|
+
{var_name} = std::move(
|
|
1039
|
+
{I}wstringification::{from_wstring}(
|
|
1040
|
+
{II}*{var_text_name}
|
|
1041
|
+
{I})
|
|
1042
|
+
);
|
|
1043
|
+
if (!{var_name}.has_value()) {{
|
|
1044
|
+
{I}std::wstring message = common::Concat(
|
|
1045
|
+
{II}L"Invalid literal for {enum_name}: ",
|
|
1046
|
+
{II}*{var_text_name}
|
|
1047
|
+
{I});
|
|
1048
|
+
|
|
1049
|
+
{I}error = common::make_optional<DeserializationError>(
|
|
1050
|
+
{II}message
|
|
1051
|
+
{I});
|
|
1052
|
+
{I}error->path.segments.emplace_front(
|
|
1053
|
+
{II}common::make_unique<PropertySegment>(
|
|
1054
|
+
{III}{cpp_common.wstring_literal(json_prop_name)}
|
|
1055
|
+
{II})
|
|
1056
|
+
{I});
|
|
1057
|
+
|
|
1058
|
+
{I}return std::make_pair<
|
|
1059
|
+
{II}common::optional<std::shared_ptr<{ok_type}> >,
|
|
1060
|
+
{II}common::optional<DeserializationError>
|
|
1061
|
+
{I}>(
|
|
1062
|
+
{II}common::nullopt,
|
|
1063
|
+
{II}std::move(error)
|
|
1064
|
+
{I});
|
|
1065
|
+
}}"""
|
|
1066
|
+
)
|
|
1067
|
+
|
|
1068
|
+
|
|
1069
|
+
def _determine_deserialize_function_to_call(cls: intermediate.ClassUnion) -> Stripped:
|
|
1070
|
+
"""
|
|
1071
|
+
Determine the function to be called to de-serialize an instance of ``cls``.
|
|
1072
|
+
|
|
1073
|
+
The result includes also template parameters, if any are necessary.
|
|
1074
|
+
"""
|
|
1075
|
+
deserialize_name = cpp_naming.function_name(Identifier(f"Deserialize_{cls.name}"))
|
|
1076
|
+
|
|
1077
|
+
interface_name = cpp_naming.interface_name(cls.name)
|
|
1078
|
+
|
|
1079
|
+
if len(cls.concrete_descendants) == 0:
|
|
1080
|
+
if len(cls.ancestors) == 0:
|
|
1081
|
+
deserialize_function = Stripped(deserialize_name)
|
|
1082
|
+
else:
|
|
1083
|
+
deserialize_function = Stripped(
|
|
1084
|
+
f"""\
|
|
1085
|
+
{deserialize_name}<
|
|
1086
|
+
{I}types::{interface_name}
|
|
1087
|
+
>"""
|
|
1088
|
+
)
|
|
1089
|
+
else:
|
|
1090
|
+
deserialize_function = Stripped(deserialize_name)
|
|
1091
|
+
|
|
1092
|
+
return deserialize_function
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
def _generate_deserialize_instance_property(
|
|
1096
|
+
prop: intermediate.Property, ok_type: Stripped
|
|
1097
|
+
) -> Stripped:
|
|
1098
|
+
"""
|
|
1099
|
+
Generate the snippet to de-serialize the instance property.
|
|
1100
|
+
|
|
1101
|
+
We assume that the check whether the property is set is performed elsewhere.
|
|
1102
|
+
|
|
1103
|
+
The ``ok_type`` denotes the type of the deserialized instance, *not* the property.
|
|
1104
|
+
We have to distinguish between cases where we directly create an upcast pointer to
|
|
1105
|
+
an ancestor class, and cases where there are no ancestor classes.
|
|
1106
|
+
"""
|
|
1107
|
+
type_anno = intermediate.beneath_optional(prop.type_annotation)
|
|
1108
|
+
assert isinstance(type_anno, intermediate.OurTypeAnnotation) and isinstance(
|
|
1109
|
+
type_anno.our_type, (intermediate.AbstractClass, intermediate.ConcreteClass)
|
|
1110
|
+
)
|
|
1111
|
+
|
|
1112
|
+
cls = type_anno.our_type
|
|
1113
|
+
|
|
1114
|
+
deserialize_function = _determine_deserialize_function_to_call(cls=cls)
|
|
1115
|
+
|
|
1116
|
+
var_name = cpp_naming.variable_name(Identifier(f"the_{prop.name}"))
|
|
1117
|
+
json_prop_name = naming.json_property(prop.name)
|
|
1118
|
+
|
|
1119
|
+
return Stripped(
|
|
1120
|
+
f"""\
|
|
1121
|
+
std::tie(
|
|
1122
|
+
{I}{var_name},
|
|
1123
|
+
{I}error
|
|
1124
|
+
) = {deserialize_function}(
|
|
1125
|
+
{I}json[{cpp_common.string_literal(json_prop_name)}],
|
|
1126
|
+
{I}additional_properties
|
|
1127
|
+
);
|
|
1128
|
+
|
|
1129
|
+
if (error.has_value()) {{
|
|
1130
|
+
{I}error->path.segments.emplace_front(
|
|
1131
|
+
{II}common::make_unique<PropertySegment>(
|
|
1132
|
+
{III}{cpp_common.wstring_literal(json_prop_name)}
|
|
1133
|
+
{II})
|
|
1134
|
+
{I});
|
|
1135
|
+
|
|
1136
|
+
{I}return std::make_pair<
|
|
1137
|
+
{II}common::optional<std::shared_ptr<{ok_type}> >,
|
|
1138
|
+
{II}common::optional<DeserializationError>
|
|
1139
|
+
{I}>(
|
|
1140
|
+
{II}common::nullopt,
|
|
1141
|
+
{II}std::move(error)
|
|
1142
|
+
{I});
|
|
1143
|
+
}}"""
|
|
1144
|
+
)
|
|
1145
|
+
|
|
1146
|
+
|
|
1147
|
+
def _generate_deserialize_list_property(
|
|
1148
|
+
prop: intermediate.Property, ok_type: Stripped
|
|
1149
|
+
) -> Stripped:
|
|
1150
|
+
"""
|
|
1151
|
+
Generate the snippet to de-serialize the list property.
|
|
1152
|
+
|
|
1153
|
+
We assume that the check whether the property is set is performed elsewhere.
|
|
1154
|
+
|
|
1155
|
+
The ``ok_type`` denotes the type of the deserialized instance, *not* the property.
|
|
1156
|
+
We have to distinguish between cases where we directly create an upcast pointer to
|
|
1157
|
+
an ancestor class, and cases where there are no ancestor classes.
|
|
1158
|
+
"""
|
|
1159
|
+
type_anno = intermediate.beneath_optional(prop.type_annotation)
|
|
1160
|
+
assert isinstance(type_anno, intermediate.ListTypeAnnotation)
|
|
1161
|
+
assert isinstance(type_anno.items, intermediate.OurTypeAnnotation) and isinstance(
|
|
1162
|
+
type_anno.items.our_type,
|
|
1163
|
+
(intermediate.AbstractClass, intermediate.ConcreteClass),
|
|
1164
|
+
), (
|
|
1165
|
+
f"NOTE (mristin, 2023-11-10): We expect only lists of classes "
|
|
1166
|
+
f"at the moment, but you specified {type_anno}. "
|
|
1167
|
+
f"Please contact the developers if you need this feature."
|
|
1168
|
+
)
|
|
1169
|
+
|
|
1170
|
+
cls = type_anno.items.our_type
|
|
1171
|
+
|
|
1172
|
+
interface_name = cpp_naming.interface_name(cls.name)
|
|
1173
|
+
|
|
1174
|
+
deserialize_function = _determine_deserialize_function_to_call(cls=cls)
|
|
1175
|
+
|
|
1176
|
+
var_name = cpp_naming.variable_name(Identifier(f"the_{prop.name}"))
|
|
1177
|
+
json_prop_name = naming.json_property(prop.name)
|
|
1178
|
+
|
|
1179
|
+
var_index_name = cpp_naming.variable_name(Identifier(f"index_{prop.name}"))
|
|
1180
|
+
var_json = cpp_naming.variable_name(Identifier(f"json_{prop.name}"))
|
|
1181
|
+
|
|
1182
|
+
return Stripped(
|
|
1183
|
+
f"""\
|
|
1184
|
+
const nlohmann::json& {var_json}(
|
|
1185
|
+
{I}json[{cpp_common.string_literal(json_prop_name)}]
|
|
1186
|
+
);
|
|
1187
|
+
if (!{var_json}.is_array()) {{
|
|
1188
|
+
{I}error = common::make_optional<DeserializationError>(
|
|
1189
|
+
{II}common::Concat(
|
|
1190
|
+
{III}L"Expected an array, but got: ",
|
|
1191
|
+
{III}common::Utf8ToWstring(
|
|
1192
|
+
{IIII}{var_json}.type_name()
|
|
1193
|
+
{III})
|
|
1194
|
+
{II})
|
|
1195
|
+
{I});
|
|
1196
|
+
|
|
1197
|
+
{I}error->path.segments.emplace_front(
|
|
1198
|
+
{II}common::make_unique<PropertySegment>(
|
|
1199
|
+
{III}{cpp_common.wstring_literal(json_prop_name)}
|
|
1200
|
+
{II})
|
|
1201
|
+
{I});
|
|
1202
|
+
|
|
1203
|
+
{I}return std::make_pair<
|
|
1204
|
+
{II}common::optional<std::shared_ptr<{ok_type}> >,
|
|
1205
|
+
{II}common::optional<DeserializationError>
|
|
1206
|
+
{I}>(
|
|
1207
|
+
{II}common::nullopt,
|
|
1208
|
+
{II}std::move(error)
|
|
1209
|
+
{I});
|
|
1210
|
+
}}
|
|
1211
|
+
|
|
1212
|
+
{var_name} = common::make_optional<
|
|
1213
|
+
{I}std::vector<
|
|
1214
|
+
{II}std::shared_ptr<types::{interface_name}>
|
|
1215
|
+
{I}>
|
|
1216
|
+
>();
|
|
1217
|
+
|
|
1218
|
+
{var_name}->reserve({var_json}.size());
|
|
1219
|
+
|
|
1220
|
+
size_t {var_index_name} = 0;
|
|
1221
|
+
|
|
1222
|
+
for (
|
|
1223
|
+
{I}const nlohmann::json& item
|
|
1224
|
+
{I}: {var_json}
|
|
1225
|
+
) {{
|
|
1226
|
+
{I}common::optional<
|
|
1227
|
+
{II}std::shared_ptr<types::{interface_name}>
|
|
1228
|
+
{I}> deserialized;
|
|
1229
|
+
|
|
1230
|
+
{I}std::tie(
|
|
1231
|
+
{II}deserialized,
|
|
1232
|
+
{II}error
|
|
1233
|
+
{I}) = {indent_but_first_line(deserialize_function, I)}(
|
|
1234
|
+
{II}item,
|
|
1235
|
+
{II}additional_properties
|
|
1236
|
+
{I});
|
|
1237
|
+
|
|
1238
|
+
{I}if (error.has_value()) {{
|
|
1239
|
+
{II}error->path.segments.emplace_front(
|
|
1240
|
+
{III}common::make_unique<IndexSegment>(
|
|
1241
|
+
{IIII}{var_index_name}
|
|
1242
|
+
{III})
|
|
1243
|
+
{II});
|
|
1244
|
+
|
|
1245
|
+
{II}error->path.segments.emplace_front(
|
|
1246
|
+
{III}common::make_unique<PropertySegment>(
|
|
1247
|
+
{IIII}{cpp_common.wstring_literal(json_prop_name)}
|
|
1248
|
+
{III})
|
|
1249
|
+
{II});
|
|
1250
|
+
|
|
1251
|
+
{II}return std::make_pair<
|
|
1252
|
+
{III}common::optional<std::shared_ptr<{ok_type}> >,
|
|
1253
|
+
{III}common::optional<DeserializationError>
|
|
1254
|
+
{II}>(
|
|
1255
|
+
{III}common::nullopt,
|
|
1256
|
+
{III}std::move(error)
|
|
1257
|
+
{II});
|
|
1258
|
+
{I}}}
|
|
1259
|
+
|
|
1260
|
+
{I}{var_name}->emplace_back(
|
|
1261
|
+
{II}std::move(*deserialized)
|
|
1262
|
+
{I});
|
|
1263
|
+
|
|
1264
|
+
{I}++{var_index_name};
|
|
1265
|
+
}}"""
|
|
1266
|
+
)
|
|
1267
|
+
|
|
1268
|
+
|
|
1269
|
+
def _generate_deserialize_property(
|
|
1270
|
+
prop: intermediate.Property, ok_type: Stripped
|
|
1271
|
+
) -> Stripped:
|
|
1272
|
+
"""
|
|
1273
|
+
Generate the snippet to de-serialize the given property.
|
|
1274
|
+
|
|
1275
|
+
The ``ok_type`` denotes the type of the deserialized instance, *not* the property.
|
|
1276
|
+
We have to distinguish between cases where we directly create an upcast pointer to
|
|
1277
|
+
an ancestor class, and cases where there are no ancestor classes.
|
|
1278
|
+
"""
|
|
1279
|
+
type_anno = intermediate.beneath_optional(prop.type_annotation)
|
|
1280
|
+
|
|
1281
|
+
code: Stripped
|
|
1282
|
+
|
|
1283
|
+
if isinstance(type_anno, intermediate.PrimitiveTypeAnnotation):
|
|
1284
|
+
code = _generate_deserialize_primitive_property(prop=prop, ok_type=ok_type)
|
|
1285
|
+
|
|
1286
|
+
elif isinstance(type_anno, intermediate.OurTypeAnnotation):
|
|
1287
|
+
if isinstance(type_anno.our_type, intermediate.Enumeration):
|
|
1288
|
+
code = _generate_deserialize_enumeration_property(
|
|
1289
|
+
prop=prop, ok_type=ok_type
|
|
1290
|
+
)
|
|
1291
|
+
|
|
1292
|
+
elif isinstance(type_anno.our_type, intermediate.ConstrainedPrimitive):
|
|
1293
|
+
code = _generate_deserialize_primitive_property(prop=prop, ok_type=ok_type)
|
|
1294
|
+
|
|
1295
|
+
elif isinstance(
|
|
1296
|
+
type_anno.our_type, (intermediate.AbstractClass, intermediate.ConcreteClass)
|
|
1297
|
+
):
|
|
1298
|
+
code = _generate_deserialize_instance_property(prop=prop, ok_type=ok_type)
|
|
1299
|
+
|
|
1300
|
+
else:
|
|
1301
|
+
assert_never(type_anno.our_type)
|
|
1302
|
+
elif isinstance(type_anno, intermediate.ListTypeAnnotation):
|
|
1303
|
+
assert isinstance(
|
|
1304
|
+
type_anno.items, intermediate.OurTypeAnnotation
|
|
1305
|
+
) and isinstance(
|
|
1306
|
+
type_anno.items.our_type,
|
|
1307
|
+
(intermediate.AbstractClass, intermediate.ConcreteClass),
|
|
1308
|
+
), (
|
|
1309
|
+
f"NOTE (mristin, 2023-11-10): We expect only lists of classes "
|
|
1310
|
+
f"at the moment, but you specified {type_anno}. "
|
|
1311
|
+
f"Please contact the developers if you need this feature."
|
|
1312
|
+
)
|
|
1313
|
+
|
|
1314
|
+
code = _generate_deserialize_list_property(prop=prop, ok_type=ok_type)
|
|
1315
|
+
else:
|
|
1316
|
+
assert_never(type_anno)
|
|
1317
|
+
|
|
1318
|
+
if isinstance(prop.type_annotation, intermediate.OptionalTypeAnnotation):
|
|
1319
|
+
json_prop_literal = cpp_common.string_literal(naming.json_property(prop.name))
|
|
1320
|
+
|
|
1321
|
+
code = Stripped(
|
|
1322
|
+
f"""\
|
|
1323
|
+
if (json.contains({json_prop_literal})) {{
|
|
1324
|
+
{I}{indent_but_first_line(code, I)}
|
|
1325
|
+
}}"""
|
|
1326
|
+
)
|
|
1327
|
+
|
|
1328
|
+
return code
|
|
1329
|
+
|
|
1330
|
+
|
|
1331
|
+
@ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
|
|
1332
|
+
def _generate_concretely_deserialize_implementation(
|
|
1333
|
+
cls: intermediate.ConcreteClass,
|
|
1334
|
+
spec_impls: specific_implementations.SpecificImplementations,
|
|
1335
|
+
) -> Tuple[Optional[Stripped], Optional[Error]]:
|
|
1336
|
+
"""
|
|
1337
|
+
Generate the concrete deserialization for the class ``cls``.
|
|
1338
|
+
|
|
1339
|
+
It is assumed that the dispatch has been already effectuated to this generated
|
|
1340
|
+
function, so no further dispatch should be performed.
|
|
1341
|
+
"""
|
|
1342
|
+
if cls.is_implementation_specific:
|
|
1343
|
+
implementation_key = specific_implementations.ImplementationKey(
|
|
1344
|
+
f"jsonization/deserialize_{cls.name}.cpp"
|
|
1345
|
+
)
|
|
1346
|
+
|
|
1347
|
+
code = spec_impls.get(implementation_key, None)
|
|
1348
|
+
if code is None:
|
|
1349
|
+
return None, Error(
|
|
1350
|
+
cls.parsed.node,
|
|
1351
|
+
f"The implementation is missing for the JSON deserialization "
|
|
1352
|
+
f"of {cls.name!r}: {implementation_key}",
|
|
1353
|
+
)
|
|
1354
|
+
return code, None
|
|
1355
|
+
|
|
1356
|
+
interface_name = cpp_naming.interface_name(cls.name)
|
|
1357
|
+
|
|
1358
|
+
if len(cls.ancestors) == 0:
|
|
1359
|
+
# NOTE (mristin, 2023-11-10):
|
|
1360
|
+
# We will not need to upcast this instance, so the return value type
|
|
1361
|
+
# is simply the interface.
|
|
1362
|
+
ok_type = Stripped(f"types::{interface_name}")
|
|
1363
|
+
else:
|
|
1364
|
+
# NOTE (mristin, 2023-11-10):
|
|
1365
|
+
# We have to leave it open to upcast to an ancestor class, and hence
|
|
1366
|
+
# we introduce a template parameter.
|
|
1367
|
+
ok_type = Stripped("T")
|
|
1368
|
+
|
|
1369
|
+
expected_properties = cpp_naming.constant_name(
|
|
1370
|
+
Identifier(f"properties_in_{cls.name}")
|
|
1371
|
+
)
|
|
1372
|
+
|
|
1373
|
+
blocks = [
|
|
1374
|
+
Stripped(
|
|
1375
|
+
f"""\
|
|
1376
|
+
if (!json.is_object()) {{
|
|
1377
|
+
{I}std::wstring message = common::Concat(
|
|
1378
|
+
{II}L"Expected an object, but got: ",
|
|
1379
|
+
{II}common::Utf8ToWstring(json.type_name())
|
|
1380
|
+
{I});
|
|
1381
|
+
|
|
1382
|
+
{I}return std::make_pair<
|
|
1383
|
+
{II}common::optional<std::shared_ptr<{ok_type}> >,
|
|
1384
|
+
{II}common::optional<DeserializationError>
|
|
1385
|
+
{I}>(
|
|
1386
|
+
{II}common::nullopt,
|
|
1387
|
+
{II}common::make_optional<DeserializationError>(
|
|
1388
|
+
{III}message
|
|
1389
|
+
{II})
|
|
1390
|
+
{I});
|
|
1391
|
+
}}"""
|
|
1392
|
+
),
|
|
1393
|
+
Stripped(
|
|
1394
|
+
f"""\
|
|
1395
|
+
if (!additional_properties) {{
|
|
1396
|
+
{I}for (const auto& key_val : json.items()) {{
|
|
1397
|
+
{II}auto it(
|
|
1398
|
+
{III}{expected_properties}.find(key_val.key())
|
|
1399
|
+
{II});
|
|
1400
|
+
{II}if (it == {expected_properties}.end()) {{
|
|
1401
|
+
{III}std::wstring message = common::Concat(
|
|
1402
|
+
{IIII}L"Unexpected additional property: ",
|
|
1403
|
+
{IIII}common::Utf8ToWstring(key_val.key())
|
|
1404
|
+
{III});
|
|
1405
|
+
|
|
1406
|
+
{III}return std::make_pair<
|
|
1407
|
+
{IIII}common::optional<std::shared_ptr<{ok_type}> >,
|
|
1408
|
+
{IIII}common::optional<DeserializationError>
|
|
1409
|
+
{III}>(
|
|
1410
|
+
{IIII}common::nullopt,
|
|
1411
|
+
{IIII}common::make_optional<DeserializationError>(
|
|
1412
|
+
{IIIII}message
|
|
1413
|
+
{IIII})
|
|
1414
|
+
{III});
|
|
1415
|
+
{II}}}
|
|
1416
|
+
{I}}}
|
|
1417
|
+
}}"""
|
|
1418
|
+
),
|
|
1419
|
+
] # type: List[Stripped]
|
|
1420
|
+
|
|
1421
|
+
class_name = cpp_naming.class_name(cls.name)
|
|
1422
|
+
|
|
1423
|
+
if len(cls.properties) == 0:
|
|
1424
|
+
blocks.append(
|
|
1425
|
+
Stripped(
|
|
1426
|
+
f"""\
|
|
1427
|
+
return std::make_pair(
|
|
1428
|
+
{I}common::make_optional<
|
|
1429
|
+
{II}std::shared_ptr<{ok_type}>
|
|
1430
|
+
{I}>(
|
|
1431
|
+
{II}// NOTE (mristin):
|
|
1432
|
+
{II}// We deliberately do not use std::make_shared here to avoid an unnecessary
|
|
1433
|
+
{II}// upcast.
|
|
1434
|
+
{II}new types::{class_name}()
|
|
1435
|
+
{I}),
|
|
1436
|
+
{I}common::nullopt
|
|
1437
|
+
);"""
|
|
1438
|
+
)
|
|
1439
|
+
)
|
|
1440
|
+
else:
|
|
1441
|
+
names_of_required_properties = [
|
|
1442
|
+
prop.name
|
|
1443
|
+
for prop in cls.properties
|
|
1444
|
+
if not isinstance(prop.type_annotation, intermediate.OptionalTypeAnnotation)
|
|
1445
|
+
]
|
|
1446
|
+
|
|
1447
|
+
if cls.serialization.with_model_type:
|
|
1448
|
+
names_of_required_properties.append(Identifier("model_type"))
|
|
1449
|
+
|
|
1450
|
+
if len(names_of_required_properties) > 0:
|
|
1451
|
+
blocks.append(Stripped("// region Check required properties"))
|
|
1452
|
+
for prop_name in names_of_required_properties:
|
|
1453
|
+
json_prop_name = naming.json_property(prop_name)
|
|
1454
|
+
json_prop_name_literal = cpp_common.string_literal(json_prop_name)
|
|
1455
|
+
blocks.append(
|
|
1456
|
+
Stripped(
|
|
1457
|
+
f"""\
|
|
1458
|
+
if (!json.contains({json_prop_name_literal})) {{
|
|
1459
|
+
{I}return std::make_pair<
|
|
1460
|
+
{II}common::optional<std::shared_ptr<{ok_type}> >,
|
|
1461
|
+
{II}common::optional<DeserializationError>
|
|
1462
|
+
{I}>(
|
|
1463
|
+
{II}common::nullopt,
|
|
1464
|
+
{II}common::make_optional<DeserializationError>(
|
|
1465
|
+
{III}L"The required property {json_prop_name} is missing"
|
|
1466
|
+
{II})
|
|
1467
|
+
{I});
|
|
1468
|
+
}}"""
|
|
1469
|
+
)
|
|
1470
|
+
)
|
|
1471
|
+
|
|
1472
|
+
blocks.append(Stripped("// endregion Check required properties"))
|
|
1473
|
+
|
|
1474
|
+
# region Initialization
|
|
1475
|
+
blocks.append(Stripped("// region Initialization"))
|
|
1476
|
+
|
|
1477
|
+
if len(cls.properties) > 0:
|
|
1478
|
+
blocks.append(Stripped("common::optional<DeserializationError> error;"))
|
|
1479
|
+
|
|
1480
|
+
init_statements = [] # type: List[Stripped]
|
|
1481
|
+
|
|
1482
|
+
for prop in cls.properties:
|
|
1483
|
+
var_name = cpp_naming.variable_name(Identifier(f"the_{prop.name}"))
|
|
1484
|
+
var_type = cpp_common.generate_type(
|
|
1485
|
+
type_annotation=prop.type_annotation,
|
|
1486
|
+
types_namespace=cpp_common.TYPES_NAMESPACE,
|
|
1487
|
+
)
|
|
1488
|
+
|
|
1489
|
+
if not isinstance(
|
|
1490
|
+
prop.type_annotation, intermediate.OptionalTypeAnnotation
|
|
1491
|
+
):
|
|
1492
|
+
if "\n" in var_type:
|
|
1493
|
+
var_type = Stripped(
|
|
1494
|
+
f"""\
|
|
1495
|
+
common::optional<
|
|
1496
|
+
{I}{indent_but_first_line(var_type, I)}
|
|
1497
|
+
>"""
|
|
1498
|
+
)
|
|
1499
|
+
else:
|
|
1500
|
+
if var_type.endswith(">"):
|
|
1501
|
+
var_type = Stripped(f"common::optional<{var_type} >")
|
|
1502
|
+
else:
|
|
1503
|
+
var_type = Stripped(f"common::optional<{var_type}>")
|
|
1504
|
+
|
|
1505
|
+
init_statements.append(Stripped(f"{var_type} {var_name};"))
|
|
1506
|
+
|
|
1507
|
+
blocks.append(Stripped("\n\n".join(init_statements)))
|
|
1508
|
+
|
|
1509
|
+
blocks.append(Stripped("// endregion Initialization"))
|
|
1510
|
+
# endregion
|
|
1511
|
+
|
|
1512
|
+
# region Deserialize properties
|
|
1513
|
+
for prop in cls.properties:
|
|
1514
|
+
json_prop_name = naming.json_property(prop.name)
|
|
1515
|
+
blocks.append(Stripped(f"// region De-serialize {json_prop_name}"))
|
|
1516
|
+
|
|
1517
|
+
blocks.append(_generate_deserialize_property(prop=prop, ok_type=ok_type))
|
|
1518
|
+
|
|
1519
|
+
blocks.append(Stripped(f"// endregion De-serialize {json_prop_name}"))
|
|
1520
|
+
# endregion
|
|
1521
|
+
|
|
1522
|
+
if cls.serialization.with_model_type:
|
|
1523
|
+
# NOTE (mristin):
|
|
1524
|
+
# If the serialization requires a model type, we consequently check for it
|
|
1525
|
+
# here. The model type thus obtained is *not* used for any dispatch. We only
|
|
1526
|
+
# use this value for verification to make sure that the model type
|
|
1527
|
+
# of the instances is consistent with the expected value for its concrete
|
|
1528
|
+
# class. This will be performed even though the code might have had to parse
|
|
1529
|
+
# model type before for the dispatch. We decided to double-check to cover
|
|
1530
|
+
# the case where a dispatch is *unnecessary* (*e.g.*, the caller knows the
|
|
1531
|
+
# expected runtime type), but the model type might still be invalid in the
|
|
1532
|
+
# input. Hence, when the dispatch is *necessary*, the model type JSON
|
|
1533
|
+
# property will be parsed twice, which is a cost we currently find
|
|
1534
|
+
# acceptable.
|
|
1535
|
+
|
|
1536
|
+
blocks.append(
|
|
1537
|
+
Stripped(
|
|
1538
|
+
"""\
|
|
1539
|
+
// region Check model type
|
|
1540
|
+
// This check is intended only for verification, not for dispatch."""
|
|
1541
|
+
)
|
|
1542
|
+
)
|
|
1543
|
+
|
|
1544
|
+
model_type = naming.json_model_type(cls.name)
|
|
1545
|
+
|
|
1546
|
+
blocks.append(
|
|
1547
|
+
Stripped(
|
|
1548
|
+
f"""\
|
|
1549
|
+
common::optional<
|
|
1550
|
+
{I}std::wstring
|
|
1551
|
+
> model_type;
|
|
1552
|
+
|
|
1553
|
+
std::tie(
|
|
1554
|
+
{I}model_type,
|
|
1555
|
+
{I}error
|
|
1556
|
+
) = DeserializeWstring(
|
|
1557
|
+
{I}json["modelType"]
|
|
1558
|
+
);
|
|
1559
|
+
|
|
1560
|
+
if (error.has_value()) {{
|
|
1561
|
+
{I}error->path.segments.emplace_front(
|
|
1562
|
+
{II}common::make_unique<PropertySegment>(
|
|
1563
|
+
{III}L"modelType"
|
|
1564
|
+
{II})
|
|
1565
|
+
{I});
|
|
1566
|
+
|
|
1567
|
+
{I}return std::make_pair<
|
|
1568
|
+
{II}common::optional<std::shared_ptr<{ok_type}> >,
|
|
1569
|
+
{II}common::optional<DeserializationError>
|
|
1570
|
+
{I}>(
|
|
1571
|
+
{II}common::nullopt,
|
|
1572
|
+
{II}std::move(error)
|
|
1573
|
+
{I});
|
|
1574
|
+
}}
|
|
1575
|
+
|
|
1576
|
+
if (*model_type != L"{model_type}") {{
|
|
1577
|
+
{I}std::wstring message = common::Concat(
|
|
1578
|
+
{II}L"Expected model type '{model_type}', "
|
|
1579
|
+
{II}L"but got: ",
|
|
1580
|
+
{II}*model_type
|
|
1581
|
+
{I});
|
|
1582
|
+
|
|
1583
|
+
{I}error = common::make_optional<DeserializationError>(
|
|
1584
|
+
{II}message
|
|
1585
|
+
{I});
|
|
1586
|
+
|
|
1587
|
+
{I}return std::make_pair<
|
|
1588
|
+
{II}common::optional<std::shared_ptr<{ok_type}> >,
|
|
1589
|
+
{II}common::optional<DeserializationError>
|
|
1590
|
+
{I}>(
|
|
1591
|
+
{II}common::nullopt,
|
|
1592
|
+
{II}std::move(error)
|
|
1593
|
+
{I});
|
|
1594
|
+
}}"""
|
|
1595
|
+
)
|
|
1596
|
+
)
|
|
1597
|
+
|
|
1598
|
+
blocks.append(Stripped("// endregion Check model type"))
|
|
1599
|
+
|
|
1600
|
+
# region Pass arguments to the constructor
|
|
1601
|
+
property_names = [prop.name for prop in cls.properties]
|
|
1602
|
+
constructor_argument_names = [arg.name for arg in cls.constructor.arguments]
|
|
1603
|
+
|
|
1604
|
+
# fmt: off
|
|
1605
|
+
assert (
|
|
1606
|
+
set(prop.name for prop in cls.properties)
|
|
1607
|
+
== set(arg.name for arg in cls.constructor.arguments)
|
|
1608
|
+
), (
|
|
1609
|
+
f"Expected the properties to coincide with constructor arguments, "
|
|
1610
|
+
f"but they do not for {cls.name!r}:"
|
|
1611
|
+
f"{property_names=}, {constructor_argument_names=}"
|
|
1612
|
+
)
|
|
1613
|
+
# fmt: on
|
|
1614
|
+
|
|
1615
|
+
constructor_args = [] # type: List[Stripped]
|
|
1616
|
+
for arg in cls.constructor.arguments:
|
|
1617
|
+
prop = cls.properties_by_name[arg.name]
|
|
1618
|
+
|
|
1619
|
+
var_name = cpp_naming.variable_name(Identifier(f"the_{prop.name}"))
|
|
1620
|
+
if isinstance(prop.type_annotation, intermediate.OptionalTypeAnnotation):
|
|
1621
|
+
constructor_args.append(Stripped(f"std::move({var_name})"))
|
|
1622
|
+
else:
|
|
1623
|
+
constructor_args.append(Stripped(f"std::move(*{var_name})"))
|
|
1624
|
+
|
|
1625
|
+
constructor_args_joined = ",\n".join(constructor_args)
|
|
1626
|
+
|
|
1627
|
+
blocks.append(
|
|
1628
|
+
Stripped(
|
|
1629
|
+
f"""\
|
|
1630
|
+
return std::make_pair(
|
|
1631
|
+
{I}common::make_optional<
|
|
1632
|
+
{II}std::shared_ptr<{ok_type}>
|
|
1633
|
+
{I}>(
|
|
1634
|
+
{II}// NOTE (mristin):
|
|
1635
|
+
{II}// We deliberately do not use std::make_shared here to avoid an unnecessary
|
|
1636
|
+
{II}// upcast.
|
|
1637
|
+
{II}new types::{class_name}(
|
|
1638
|
+
{III}{indent_but_first_line(constructor_args_joined, III)}
|
|
1639
|
+
{II})
|
|
1640
|
+
{I}),
|
|
1641
|
+
{I}common::nullopt
|
|
1642
|
+
);"""
|
|
1643
|
+
)
|
|
1644
|
+
)
|
|
1645
|
+
# endregion
|
|
1646
|
+
|
|
1647
|
+
body = "\n\n".join(blocks)
|
|
1648
|
+
|
|
1649
|
+
if len(cls.concrete_descendants) == 0:
|
|
1650
|
+
function_name = cpp_naming.function_name(Identifier(f"deserialize_{cls.name}"))
|
|
1651
|
+
else:
|
|
1652
|
+
function_name = cpp_naming.function_name(
|
|
1653
|
+
Identifier(f"concretely_deserialize_{cls.name}")
|
|
1654
|
+
)
|
|
1655
|
+
|
|
1656
|
+
if len(cls.ancestors) > 0:
|
|
1657
|
+
# NOTE (mristin, 2023-11-10):
|
|
1658
|
+
# We have to introduce the template so that we do not have to
|
|
1659
|
+
# unnecessarily upcast the instance to ancestor classes.
|
|
1660
|
+
prefix = Stripped(
|
|
1661
|
+
f"""\
|
|
1662
|
+
template <
|
|
1663
|
+
{I}typename T,
|
|
1664
|
+
{I}typename std::enable_if<
|
|
1665
|
+
{II}std::is_base_of<T, types::{interface_name}>::value
|
|
1666
|
+
{I}>::type*
|
|
1667
|
+
>
|
|
1668
|
+
std::pair<
|
|
1669
|
+
{I}common::optional<std::shared_ptr<T> >,
|
|
1670
|
+
{I}common::optional<DeserializationError>
|
|
1671
|
+
>"""
|
|
1672
|
+
)
|
|
1673
|
+
else:
|
|
1674
|
+
prefix = Stripped(
|
|
1675
|
+
f"""\
|
|
1676
|
+
std::pair<
|
|
1677
|
+
{I}common::optional<
|
|
1678
|
+
{II}std::shared_ptr<types::{interface_name}>
|
|
1679
|
+
{I}>,
|
|
1680
|
+
{I}common::optional<DeserializationError>
|
|
1681
|
+
>"""
|
|
1682
|
+
)
|
|
1683
|
+
|
|
1684
|
+
expected_properties_literals = [
|
|
1685
|
+
f"{cpp_common.string_literal(naming.json_property(prop.name))}"
|
|
1686
|
+
for prop in cls.properties
|
|
1687
|
+
]
|
|
1688
|
+
|
|
1689
|
+
if cls.serialization.with_model_type:
|
|
1690
|
+
expected_properties_literals.append(cpp_common.string_literal("modelType"))
|
|
1691
|
+
|
|
1692
|
+
expected_properties_literals_joined = ",\n".join(expected_properties_literals)
|
|
1693
|
+
|
|
1694
|
+
expected_properties_definition = Stripped(
|
|
1695
|
+
f"""\
|
|
1696
|
+
std::set<std::string> {expected_properties} = {{
|
|
1697
|
+
{I}{indent_but_first_line(expected_properties_literals_joined, I)}
|
|
1698
|
+
}};"""
|
|
1699
|
+
)
|
|
1700
|
+
|
|
1701
|
+
return (
|
|
1702
|
+
Stripped(
|
|
1703
|
+
f"""\
|
|
1704
|
+
{expected_properties_definition}
|
|
1705
|
+
|
|
1706
|
+
{prefix} {function_name}(
|
|
1707
|
+
{I}const nlohmann::json& json,
|
|
1708
|
+
{I}bool additional_properties
|
|
1709
|
+
) {{
|
|
1710
|
+
{I}{indent_but_first_line(body, I)}
|
|
1711
|
+
}}"""
|
|
1712
|
+
),
|
|
1713
|
+
None,
|
|
1714
|
+
)
|
|
1715
|
+
|
|
1716
|
+
|
|
1717
|
+
@require(
|
|
1718
|
+
lambda cls: len(cls.concrete_descendants) > 0,
|
|
1719
|
+
"No dispatch possible without concrete descendants",
|
|
1720
|
+
)
|
|
1721
|
+
def _generate_dispatch_deserialize_implementation(
|
|
1722
|
+
cls: intermediate.ClassUnion,
|
|
1723
|
+
) -> List[Stripped]:
|
|
1724
|
+
"""Generate the impl. of the dispatching deserialization function for ``cls``."""
|
|
1725
|
+
targets: Iterable[intermediate.ConcreteClass]
|
|
1726
|
+
|
|
1727
|
+
if isinstance(cls, intermediate.ConcreteClass):
|
|
1728
|
+
targets = itertools.chain([cls], cls.concrete_descendants)
|
|
1729
|
+
else:
|
|
1730
|
+
targets = cls.concrete_descendants
|
|
1731
|
+
|
|
1732
|
+
assert targets is not None
|
|
1733
|
+
|
|
1734
|
+
interface_name = cpp_naming.interface_name(cls.name)
|
|
1735
|
+
|
|
1736
|
+
entries = [] # type: List[Stripped]
|
|
1737
|
+
for target_cls in targets:
|
|
1738
|
+
model_type = naming.json_model_type(target_cls.name)
|
|
1739
|
+
|
|
1740
|
+
if len(target_cls.concrete_descendants) > 0:
|
|
1741
|
+
target_function = Stripped(
|
|
1742
|
+
cpp_naming.function_name(
|
|
1743
|
+
Identifier(f"concretely_deserialize_{target_cls.name}")
|
|
1744
|
+
)
|
|
1745
|
+
)
|
|
1746
|
+
else:
|
|
1747
|
+
target_function = Stripped(
|
|
1748
|
+
cpp_naming.function_name(Identifier(f"deserialize_{target_cls.name}"))
|
|
1749
|
+
)
|
|
1750
|
+
|
|
1751
|
+
target_function = Stripped(
|
|
1752
|
+
f"""\
|
|
1753
|
+
{target_function}<
|
|
1754
|
+
{I}types::{interface_name}
|
|
1755
|
+
>"""
|
|
1756
|
+
)
|
|
1757
|
+
|
|
1758
|
+
entries.append(
|
|
1759
|
+
Stripped(
|
|
1760
|
+
f"""\
|
|
1761
|
+
{{
|
|
1762
|
+
{I}{indent_but_first_line(cpp_common.string_literal(model_type), I)},
|
|
1763
|
+
{I}{indent_but_first_line(target_function, I)}
|
|
1764
|
+
}}"""
|
|
1765
|
+
)
|
|
1766
|
+
)
|
|
1767
|
+
|
|
1768
|
+
entries_joined = ",\n".join(entries)
|
|
1769
|
+
|
|
1770
|
+
dispatch_name = cpp_naming.constant_name(
|
|
1771
|
+
Identifier(f"deserialize_{cls.name}_by_model_type")
|
|
1772
|
+
)
|
|
1773
|
+
|
|
1774
|
+
function_name = cpp_naming.function_name(Identifier(f"deserialize_{cls.name}"))
|
|
1775
|
+
|
|
1776
|
+
return [
|
|
1777
|
+
Stripped(
|
|
1778
|
+
f"""\
|
|
1779
|
+
std::map<
|
|
1780
|
+
{I}std::string,
|
|
1781
|
+
{I}std::function<
|
|
1782
|
+
{II}std::pair<
|
|
1783
|
+
{III}common::optional<std::shared_ptr<types::{interface_name}> >,
|
|
1784
|
+
{III}common::optional<DeserializationError>
|
|
1785
|
+
{II}>(const nlohmann::json&, bool)
|
|
1786
|
+
{I}>
|
|
1787
|
+
> {dispatch_name} = {{
|
|
1788
|
+
{I}{indent_but_first_line(entries_joined, I)}
|
|
1789
|
+
}};"""
|
|
1790
|
+
),
|
|
1791
|
+
Stripped(
|
|
1792
|
+
f"""\
|
|
1793
|
+
std::pair<
|
|
1794
|
+
{I}common::optional<
|
|
1795
|
+
{II}std::shared_ptr<types::{interface_name}>
|
|
1796
|
+
{I}>,
|
|
1797
|
+
{I}common::optional<DeserializationError>
|
|
1798
|
+
> {function_name}(
|
|
1799
|
+
{I}const nlohmann::json& json,
|
|
1800
|
+
{I}bool additional_properties
|
|
1801
|
+
) {{
|
|
1802
|
+
{I}const std::string* model_type;
|
|
1803
|
+
{I}common::optional<DeserializationError> error;
|
|
1804
|
+
|
|
1805
|
+
{I}std::tie(
|
|
1806
|
+
{II}model_type,
|
|
1807
|
+
{II}error
|
|
1808
|
+
{I}) = GetModelTypeFrom(json);
|
|
1809
|
+
|
|
1810
|
+
{I}if (error.has_value()) {{
|
|
1811
|
+
{II}return std::make_pair<
|
|
1812
|
+
{III}common::optional<std::shared_ptr<types::{interface_name}> >,
|
|
1813
|
+
{III}common::optional<DeserializationError>
|
|
1814
|
+
{II}>(
|
|
1815
|
+
{III}common::nullopt,
|
|
1816
|
+
{III}std::move(error)
|
|
1817
|
+
{II});
|
|
1818
|
+
{I}}}
|
|
1819
|
+
|
|
1820
|
+
{I}const auto it = {dispatch_name}.find(*model_type);
|
|
1821
|
+
{I}if (it == {dispatch_name}.end()) {{
|
|
1822
|
+
{II}std::wstring message = common::Concat(
|
|
1823
|
+
{III}L"The dispatch to the JSON de-serialization of "
|
|
1824
|
+
{III}L"types::{interface_name} "
|
|
1825
|
+
{III}L"is not defined for model type: ",
|
|
1826
|
+
{III}common::Utf8ToWstring(*model_type)
|
|
1827
|
+
{II});
|
|
1828
|
+
|
|
1829
|
+
{II}return std::make_pair<
|
|
1830
|
+
{III}common::optional<std::shared_ptr<types::{interface_name}> >,
|
|
1831
|
+
{III}common::optional<DeserializationError>
|
|
1832
|
+
{II}>(
|
|
1833
|
+
{III}common::nullopt,
|
|
1834
|
+
{III}common::make_optional<DeserializationError>(
|
|
1835
|
+
{IIII}message
|
|
1836
|
+
{III})
|
|
1837
|
+
{II});
|
|
1838
|
+
{I}}}
|
|
1839
|
+
|
|
1840
|
+
{I}return (it->second)(json, additional_properties);
|
|
1841
|
+
}}"""
|
|
1842
|
+
),
|
|
1843
|
+
]
|
|
1844
|
+
|
|
1845
|
+
|
|
1846
|
+
def _generate_deserialization_implementation(cls: intermediate.ClassUnion) -> Stripped:
|
|
1847
|
+
"""Generate the implementation of ``*From`` function."""
|
|
1848
|
+
deserialize_function = _determine_deserialize_function_to_call(cls=cls)
|
|
1849
|
+
|
|
1850
|
+
interface_name = cpp_naming.interface_name(cls.name)
|
|
1851
|
+
|
|
1852
|
+
deserialization_name = cpp_naming.function_name(Identifier(f"{cls.name}_from"))
|
|
1853
|
+
|
|
1854
|
+
return Stripped(
|
|
1855
|
+
f"""\
|
|
1856
|
+
common::expected<
|
|
1857
|
+
{I}std::shared_ptr<types::{interface_name}>,
|
|
1858
|
+
{I}DeserializationError
|
|
1859
|
+
> {deserialization_name}(
|
|
1860
|
+
{I}const nlohmann::json& json,
|
|
1861
|
+
{I}bool additional_properties
|
|
1862
|
+
) {{
|
|
1863
|
+
{I}common::optional<
|
|
1864
|
+
{II}std::shared_ptr<types::{interface_name}>
|
|
1865
|
+
{I}> instance;
|
|
1866
|
+
|
|
1867
|
+
{I}common::optional<DeserializationError> error;
|
|
1868
|
+
|
|
1869
|
+
{I}std::tie(
|
|
1870
|
+
{II}instance,
|
|
1871
|
+
{II}error
|
|
1872
|
+
{I}) = {indent_but_first_line(deserialize_function, I)}(
|
|
1873
|
+
{II}json,
|
|
1874
|
+
{II}additional_properties
|
|
1875
|
+
{I});
|
|
1876
|
+
|
|
1877
|
+
{I}if (instance.has_value()) {{
|
|
1878
|
+
{II}return std::move(*instance);
|
|
1879
|
+
{I}}}
|
|
1880
|
+
|
|
1881
|
+
{I}if (!error.has_value()) {{
|
|
1882
|
+
{II}throw std::logic_error(
|
|
1883
|
+
{III}"Unexpected null error when null instance."
|
|
1884
|
+
{II});
|
|
1885
|
+
{I}}}
|
|
1886
|
+
{I}return common::make_unexpected(
|
|
1887
|
+
{II}std::move(*error)
|
|
1888
|
+
{I});
|
|
1889
|
+
}}"""
|
|
1890
|
+
)
|
|
1891
|
+
|
|
1892
|
+
|
|
1893
|
+
def _generate_serialization_exception_implementation() -> List[Stripped]:
|
|
1894
|
+
"""Generate the implementation of the ``SerializationException``."""
|
|
1895
|
+
return [
|
|
1896
|
+
Stripped("// region SerializationException"),
|
|
1897
|
+
Stripped(
|
|
1898
|
+
f"""\
|
|
1899
|
+
std::string RenderSerializationErrorMessage(
|
|
1900
|
+
{I}const std::wstring& cause,
|
|
1901
|
+
{I}const iteration::Path& path
|
|
1902
|
+
) {{
|
|
1903
|
+
{I}return common::WstringToUtf8(
|
|
1904
|
+
{II}common::Concat(
|
|
1905
|
+
{III}L"Serialization failed at ",
|
|
1906
|
+
{III}path.ToWstring(),
|
|
1907
|
+
{III}L": ",
|
|
1908
|
+
{III}cause
|
|
1909
|
+
{II})
|
|
1910
|
+
{I});
|
|
1911
|
+
}}"""
|
|
1912
|
+
),
|
|
1913
|
+
Stripped(
|
|
1914
|
+
f"""\
|
|
1915
|
+
SerializationException::SerializationException(
|
|
1916
|
+
{I}std::wstring cause,
|
|
1917
|
+
{I}iteration::Path path
|
|
1918
|
+
) :
|
|
1919
|
+
{I}cause_(std::move(cause)),
|
|
1920
|
+
{I}path_(std::move(path)),
|
|
1921
|
+
{I}msg_(RenderSerializationErrorMessage(cause, path)) {{
|
|
1922
|
+
{I}// Intentionally empty.
|
|
1923
|
+
}}"""
|
|
1924
|
+
),
|
|
1925
|
+
Stripped(
|
|
1926
|
+
f"""\
|
|
1927
|
+
const char* SerializationException::what() const noexcept {{
|
|
1928
|
+
{I}return msg_.c_str();
|
|
1929
|
+
}}"""
|
|
1930
|
+
),
|
|
1931
|
+
Stripped(
|
|
1932
|
+
f"""\
|
|
1933
|
+
const std::wstring& SerializationException::cause() const noexcept {{
|
|
1934
|
+
{I}return cause_;
|
|
1935
|
+
}}"""
|
|
1936
|
+
),
|
|
1937
|
+
Stripped(
|
|
1938
|
+
f"""\
|
|
1939
|
+
const iteration::Path& SerializationException::path() const noexcept {{
|
|
1940
|
+
{I}return path_;
|
|
1941
|
+
}}"""
|
|
1942
|
+
),
|
|
1943
|
+
Stripped("// endregion SerializationException"),
|
|
1944
|
+
]
|
|
1945
|
+
|
|
1946
|
+
|
|
1947
|
+
def _generate_serialize_int() -> Stripped:
|
|
1948
|
+
"""Generate the function to serialize an integer to a JSON value."""
|
|
1949
|
+
return Stripped(
|
|
1950
|
+
f"""\
|
|
1951
|
+
/**
|
|
1952
|
+
* \\brief Serialize the given number to a JSON value.
|
|
1953
|
+
*
|
|
1954
|
+
* We verify that the integer is within the range representable by 64-bit floats
|
|
1955
|
+
* for interoperability with other de-serializers.
|
|
1956
|
+
*/
|
|
1957
|
+
std::pair<
|
|
1958
|
+
{I}common::optional<nlohmann::json>,
|
|
1959
|
+
{I}common::optional<SerializationError>
|
|
1960
|
+
> SerializeInt64(int64_t value) {{
|
|
1961
|
+
{I}if (
|
|
1962
|
+
{II}value < -9007199254740991L
|
|
1963
|
+
{II}|| value > 9007199254740991L
|
|
1964
|
+
{I}) {{
|
|
1965
|
+
{II}const std::wstring message = common::Concat(
|
|
1966
|
+
{III}L"The integer ",
|
|
1967
|
+
{III}std::to_wstring(value),
|
|
1968
|
+
{III}L" can not be serialized to JSON "
|
|
1969
|
+
{III}L"as it is outside the range [-2^53 + 1, 2^53 - 1] and can not "
|
|
1970
|
+
{III}L"be exactly represented as a 64-bit floating point number."
|
|
1971
|
+
{II});
|
|
1972
|
+
|
|
1973
|
+
{II}return std::make_pair<
|
|
1974
|
+
{III}common::optional<nlohmann::json>,
|
|
1975
|
+
{III}common::optional<SerializationError>
|
|
1976
|
+
{II}>(
|
|
1977
|
+
{III}common::nullopt,
|
|
1978
|
+
{III}common::make_optional<SerializationError>(
|
|
1979
|
+
{IIII}message
|
|
1980
|
+
{III})
|
|
1981
|
+
{II});
|
|
1982
|
+
{I}}}
|
|
1983
|
+
|
|
1984
|
+
{I}return std::make_pair<
|
|
1985
|
+
{II}common::optional<nlohmann::json>,
|
|
1986
|
+
{II}common::optional<SerializationError>
|
|
1987
|
+
{I}>(
|
|
1988
|
+
{II}common::make_optional<nlohmann::json>(value),
|
|
1989
|
+
{II}common::nullopt
|
|
1990
|
+
{I});
|
|
1991
|
+
}}"""
|
|
1992
|
+
)
|
|
1993
|
+
|
|
1994
|
+
|
|
1995
|
+
def _generate_serialize_str() -> Stripped:
|
|
1996
|
+
"""Generate the function to serialize a wide string to a JSON value."""
|
|
1997
|
+
return Stripped(
|
|
1998
|
+
f"""\
|
|
1999
|
+
/**
|
|
2000
|
+
* Serialize the given text to a JSON value.
|
|
2001
|
+
*/
|
|
2002
|
+
nlohmann::json SerializeWstring(
|
|
2003
|
+
{I}const std::wstring& text
|
|
2004
|
+
) {{
|
|
2005
|
+
{I}return nlohmann::json(
|
|
2006
|
+
{II}common::WstringToUtf8(text)
|
|
2007
|
+
{I});
|
|
2008
|
+
}}"""
|
|
2009
|
+
)
|
|
2010
|
+
|
|
2011
|
+
|
|
2012
|
+
def _generate_serialize_bytearray() -> Stripped:
|
|
2013
|
+
"""Generate the function to serialize a byte array to a JSON value."""
|
|
2014
|
+
return Stripped(
|
|
2015
|
+
f"""\
|
|
2016
|
+
/**
|
|
2017
|
+
* Serialize the given bytes to a JSON value.
|
|
2018
|
+
*/
|
|
2019
|
+
nlohmann::json SerializeByteArray(
|
|
2020
|
+
{I}const std::vector<std::uint8_t>& bytes
|
|
2021
|
+
) {{
|
|
2022
|
+
{I}return nlohmann::json(
|
|
2023
|
+
{II}std::move(
|
|
2024
|
+
{III}stringification::Base64Encode(bytes)
|
|
2025
|
+
{II})
|
|
2026
|
+
{I});
|
|
2027
|
+
}}"""
|
|
2028
|
+
)
|
|
2029
|
+
|
|
2030
|
+
|
|
2031
|
+
def _generate_serialize_iclass_definition() -> Stripped:
|
|
2032
|
+
"""Generate the definition of the main dispatch for serializing ``IClass``."""
|
|
2033
|
+
return Stripped(
|
|
2034
|
+
f"""\
|
|
2035
|
+
std::pair<
|
|
2036
|
+
{I}common::optional<nlohmann::json>,
|
|
2037
|
+
{I}common::optional<SerializationError>
|
|
2038
|
+
> SerializeIClass(
|
|
2039
|
+
{I}const types::IClass& that
|
|
2040
|
+
);"""
|
|
2041
|
+
)
|
|
2042
|
+
|
|
2043
|
+
|
|
2044
|
+
def _generate_serialize_primitive_property(
|
|
2045
|
+
getter_expr: str,
|
|
2046
|
+
primitive_type: intermediate.PrimitiveType,
|
|
2047
|
+
property_name: Identifier,
|
|
2048
|
+
) -> Stripped:
|
|
2049
|
+
"""
|
|
2050
|
+
Generate the snippet to serialize the given primitive property.
|
|
2051
|
+
|
|
2052
|
+
The ``getter_expr`` refers to the C++ expression specifying the value
|
|
2053
|
+
to be serialized.
|
|
2054
|
+
|
|
2055
|
+
The ``property_name`` refers to the intermediate property name.
|
|
2056
|
+
"""
|
|
2057
|
+
json_prop_name_literal = cpp_common.string_literal(
|
|
2058
|
+
naming.json_property(property_name)
|
|
2059
|
+
)
|
|
2060
|
+
|
|
2061
|
+
if primitive_type is intermediate.PrimitiveType.BOOL:
|
|
2062
|
+
return Stripped(f"result[{json_prop_name_literal}] = {getter_expr};")
|
|
2063
|
+
|
|
2064
|
+
elif primitive_type is intermediate.PrimitiveType.INT:
|
|
2065
|
+
serialized_var = cpp_naming.variable_name(Identifier(f"json_{property_name}"))
|
|
2066
|
+
return Stripped(
|
|
2067
|
+
f"""\
|
|
2068
|
+
common::optional<nlohmann::json> {serialized_var};
|
|
2069
|
+
std::tie(
|
|
2070
|
+
{I}{serialized_var},
|
|
2071
|
+
{I}error
|
|
2072
|
+
) = SerializeInt64(
|
|
2073
|
+
{I}{indent_but_first_line(getter_expr, I)}
|
|
2074
|
+
);
|
|
2075
|
+
if (error.has_value()) {{
|
|
2076
|
+
{I}error->path.segments.emplace_front(
|
|
2077
|
+
{II}common::make_unique<iteration::PropertySegment>(
|
|
2078
|
+
{III}iteration::Property::{cpp_naming.enum_literal_name(property_name)}
|
|
2079
|
+
{II})
|
|
2080
|
+
{I});
|
|
2081
|
+
|
|
2082
|
+
{I}return std::make_pair<
|
|
2083
|
+
{II}common::optional<nlohmann::json>,
|
|
2084
|
+
{II}common::optional<SerializationError>
|
|
2085
|
+
{I}>(
|
|
2086
|
+
{II}common::nullopt,
|
|
2087
|
+
{II}std::move(error)
|
|
2088
|
+
{I});
|
|
2089
|
+
}}
|
|
2090
|
+
|
|
2091
|
+
result[{json_prop_name_literal}] = std::move(
|
|
2092
|
+
{I}{serialized_var}
|
|
2093
|
+
);"""
|
|
2094
|
+
)
|
|
2095
|
+
elif primitive_type is intermediate.PrimitiveType.FLOAT:
|
|
2096
|
+
return Stripped(
|
|
2097
|
+
f"""\
|
|
2098
|
+
result[{json_prop_name_literal}] = {getter_expr};"""
|
|
2099
|
+
)
|
|
2100
|
+
|
|
2101
|
+
elif primitive_type is intermediate.PrimitiveType.STR:
|
|
2102
|
+
serialized_var = cpp_naming.variable_name(Identifier(f"json_{property_name}"))
|
|
2103
|
+
return Stripped(
|
|
2104
|
+
f"""\
|
|
2105
|
+
result[{json_prop_name_literal}] = SerializeWstring(
|
|
2106
|
+
{I}{indent_but_first_line(getter_expr, II)}
|
|
2107
|
+
);"""
|
|
2108
|
+
)
|
|
2109
|
+
|
|
2110
|
+
elif primitive_type is intermediate.PrimitiveType.BYTEARRAY:
|
|
2111
|
+
return Stripped(
|
|
2112
|
+
f"""\
|
|
2113
|
+
result[{json_prop_name_literal}] = stringification::Base64Encode(
|
|
2114
|
+
{I}{getter_expr}
|
|
2115
|
+
);"""
|
|
2116
|
+
)
|
|
2117
|
+
else:
|
|
2118
|
+
assert_never(primitive_type)
|
|
2119
|
+
|
|
2120
|
+
|
|
2121
|
+
def _generate_serialize_property(prop: intermediate.Property) -> Stripped:
|
|
2122
|
+
"""Generate the code snippet to serialize the property ``prop``."""
|
|
2123
|
+
type_anno = intermediate.beneath_optional(prop.type_annotation)
|
|
2124
|
+
|
|
2125
|
+
code = None # type: Optional[Stripped]
|
|
2126
|
+
|
|
2127
|
+
getter = cpp_naming.getter_name(prop.name)
|
|
2128
|
+
maybe_var = None
|
|
2129
|
+
if isinstance(prop.type_annotation, intermediate.OptionalTypeAnnotation):
|
|
2130
|
+
maybe_var = cpp_naming.variable_name(Identifier(f"maybe_{prop.name}"))
|
|
2131
|
+
getter_expr = f"*{maybe_var}"
|
|
2132
|
+
else:
|
|
2133
|
+
getter_expr = f"that.{getter}()"
|
|
2134
|
+
|
|
2135
|
+
json_prop_name = naming.json_property(prop.name)
|
|
2136
|
+
|
|
2137
|
+
if isinstance(type_anno, intermediate.PrimitiveTypeAnnotation):
|
|
2138
|
+
code = _generate_serialize_primitive_property(
|
|
2139
|
+
getter_expr=getter_expr,
|
|
2140
|
+
primitive_type=type_anno.a_type,
|
|
2141
|
+
property_name=prop.name,
|
|
2142
|
+
)
|
|
2143
|
+
|
|
2144
|
+
elif isinstance(type_anno, intermediate.OurTypeAnnotation):
|
|
2145
|
+
if isinstance(type_anno.our_type, intermediate.Enumeration):
|
|
2146
|
+
code = Stripped(
|
|
2147
|
+
f"""\
|
|
2148
|
+
result[{cpp_common.string_literal(json_prop_name)}] = stringification::to_string(
|
|
2149
|
+
{I}{indent_but_first_line(getter_expr, I)}
|
|
2150
|
+
);"""
|
|
2151
|
+
)
|
|
2152
|
+
elif isinstance(type_anno.our_type, intermediate.ConstrainedPrimitive):
|
|
2153
|
+
code = _generate_serialize_primitive_property(
|
|
2154
|
+
getter_expr=getter_expr,
|
|
2155
|
+
primitive_type=type_anno.our_type.constrainee,
|
|
2156
|
+
property_name=prop.name,
|
|
2157
|
+
)
|
|
2158
|
+
elif isinstance(
|
|
2159
|
+
type_anno.our_type, (intermediate.AbstractClass, intermediate.ConcreteClass)
|
|
2160
|
+
):
|
|
2161
|
+
serialized_var = cpp_naming.variable_name(Identifier(f"json_{prop.name}"))
|
|
2162
|
+
|
|
2163
|
+
code = Stripped(
|
|
2164
|
+
f"""\
|
|
2165
|
+
common::optional<nlohmann::json> {serialized_var};
|
|
2166
|
+
std::tie(
|
|
2167
|
+
{I}{serialized_var},
|
|
2168
|
+
{I}error
|
|
2169
|
+
) = SerializeIClass(
|
|
2170
|
+
{I}*{indent_but_first_line(getter_expr, I)}
|
|
2171
|
+
);
|
|
2172
|
+
if (error.has_value()) {{
|
|
2173
|
+
{I}error->path.segments.emplace_front(
|
|
2174
|
+
{II}common::make_unique<iteration::PropertySegment>(
|
|
2175
|
+
{III}iteration::Property::{cpp_naming.enum_literal_name(prop.name)}
|
|
2176
|
+
{II})
|
|
2177
|
+
{I});
|
|
2178
|
+
|
|
2179
|
+
{I}return std::make_pair<
|
|
2180
|
+
{II}common::optional<nlohmann::json>,
|
|
2181
|
+
{II}common::optional<SerializationError>
|
|
2182
|
+
{I}>(
|
|
2183
|
+
{II}common::nullopt,
|
|
2184
|
+
{II}std::move(error)
|
|
2185
|
+
{I});
|
|
2186
|
+
}}
|
|
2187
|
+
|
|
2188
|
+
result[{cpp_common.string_literal(json_prop_name)}] = std::move(
|
|
2189
|
+
{I}*{serialized_var}
|
|
2190
|
+
);"""
|
|
2191
|
+
)
|
|
2192
|
+
else:
|
|
2193
|
+
assert_never(type_anno.our_type)
|
|
2194
|
+
elif isinstance(type_anno, intermediate.ListTypeAnnotation):
|
|
2195
|
+
assert isinstance(
|
|
2196
|
+
type_anno.items, intermediate.OurTypeAnnotation
|
|
2197
|
+
) and isinstance(
|
|
2198
|
+
type_anno.items.our_type,
|
|
2199
|
+
(intermediate.AbstractClass, intermediate.ConcreteClass),
|
|
2200
|
+
), (
|
|
2201
|
+
f"NOTE (mristin, 2023-11-21): We expect only lists of classes "
|
|
2202
|
+
f"at the moment, but you specified {type_anno}. "
|
|
2203
|
+
f"Please contact the developers if you need this feature."
|
|
2204
|
+
)
|
|
2205
|
+
|
|
2206
|
+
if isinstance(prop.type_annotation, intermediate.OptionalTypeAnnotation):
|
|
2207
|
+
assert maybe_var is not None
|
|
2208
|
+
size_expr = f"{maybe_var}->size()"
|
|
2209
|
+
else:
|
|
2210
|
+
size_expr = f"that.{getter}().size()"
|
|
2211
|
+
|
|
2212
|
+
serialized_var = cpp_naming.variable_name(Identifier(f"json_{prop.name}"))
|
|
2213
|
+
|
|
2214
|
+
const_ref_item_type = cpp_common.generate_type_with_const_ref_if_applicable(
|
|
2215
|
+
type_annotation=type_anno.items, types_namespace=cpp_common.TYPES_NAMESPACE
|
|
2216
|
+
)
|
|
2217
|
+
|
|
2218
|
+
index_var = cpp_naming.variable_name(Identifier(f"index_{prop.name}"))
|
|
2219
|
+
code = Stripped(
|
|
2220
|
+
f"""\
|
|
2221
|
+
nlohmann::json {serialized_var} = nlohmann::json::array();
|
|
2222
|
+
{serialized_var}.get_ptr<nlohmann::json::array_t*>()->reserve(
|
|
2223
|
+
{I}{indent_but_first_line(size_expr, I)}
|
|
2224
|
+
);
|
|
2225
|
+
size_t {index_var} = 0;
|
|
2226
|
+
for (
|
|
2227
|
+
{I}{const_ref_item_type} item
|
|
2228
|
+
{I}: {getter_expr}
|
|
2229
|
+
) {{
|
|
2230
|
+
{I}common::optional<nlohmann::json> json_item;
|
|
2231
|
+
{I}std::tie(
|
|
2232
|
+
{II}json_item,
|
|
2233
|
+
{II}error
|
|
2234
|
+
{I}) = SerializeIClass(*item);
|
|
2235
|
+
|
|
2236
|
+
{I}if (error.has_value()) {{
|
|
2237
|
+
{II}error->path.segments.emplace_front(
|
|
2238
|
+
{III}common::make_unique<iteration::IndexSegment>(
|
|
2239
|
+
{IIII}{index_var}
|
|
2240
|
+
{III})
|
|
2241
|
+
{II});
|
|
2242
|
+
|
|
2243
|
+
{II}error->path.segments.emplace_front(
|
|
2244
|
+
{III}common::make_unique<iteration::PropertySegment>(
|
|
2245
|
+
{IIII}iteration::Property::{cpp_naming.enum_literal_name(prop.name)}
|
|
2246
|
+
{III})
|
|
2247
|
+
{II});
|
|
2248
|
+
|
|
2249
|
+
{II}return std::make_pair<
|
|
2250
|
+
{III}common::optional<nlohmann::json>,
|
|
2251
|
+
{III}common::optional<SerializationError>
|
|
2252
|
+
{II}>(
|
|
2253
|
+
{III}common::nullopt,
|
|
2254
|
+
{III}std::move(error)
|
|
2255
|
+
{II});
|
|
2256
|
+
{I}}}
|
|
2257
|
+
|
|
2258
|
+
{I}{serialized_var}.emplace_back(
|
|
2259
|
+
{II}std::move(*json_item)
|
|
2260
|
+
{I});
|
|
2261
|
+
|
|
2262
|
+
{I}++{index_var};
|
|
2263
|
+
}}
|
|
2264
|
+
result[{cpp_common.string_literal(json_prop_name)}] = std::move(
|
|
2265
|
+
{I}{serialized_var}
|
|
2266
|
+
);"""
|
|
2267
|
+
)
|
|
2268
|
+
else:
|
|
2269
|
+
assert_never(type_anno)
|
|
2270
|
+
|
|
2271
|
+
assert code is not None
|
|
2272
|
+
|
|
2273
|
+
if isinstance(prop.type_annotation, intermediate.OptionalTypeAnnotation):
|
|
2274
|
+
maybe_var_type = cpp_common.generate_type_with_const_ref_if_applicable(
|
|
2275
|
+
type_annotation=prop.type_annotation,
|
|
2276
|
+
types_namespace=cpp_common.TYPES_NAMESPACE,
|
|
2277
|
+
)
|
|
2278
|
+
|
|
2279
|
+
assert maybe_var is not None
|
|
2280
|
+
|
|
2281
|
+
code = Stripped(
|
|
2282
|
+
f"""\
|
|
2283
|
+
{maybe_var_type} {maybe_var}(
|
|
2284
|
+
{I}that.{getter}()
|
|
2285
|
+
);
|
|
2286
|
+
if ({maybe_var}.has_value()) {{
|
|
2287
|
+
{I}{indent_but_first_line(code, I)}
|
|
2288
|
+
}}"""
|
|
2289
|
+
)
|
|
2290
|
+
|
|
2291
|
+
return code
|
|
2292
|
+
|
|
2293
|
+
|
|
2294
|
+
@ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
|
|
2295
|
+
def _generate_serialize_cls(
|
|
2296
|
+
cls: intermediate.ConcreteClass,
|
|
2297
|
+
spec_impls: specific_implementations.SpecificImplementations,
|
|
2298
|
+
) -> Tuple[Optional[Stripped], Optional[Error]]:
|
|
2299
|
+
"""Generate the serialization function for the class ``cls``."""
|
|
2300
|
+
if cls.is_implementation_specific:
|
|
2301
|
+
implementation_key = specific_implementations.ImplementationKey(
|
|
2302
|
+
f"jsonization/serialize_{cls.name}.cpp"
|
|
2303
|
+
)
|
|
2304
|
+
|
|
2305
|
+
code = spec_impls.get(implementation_key, None)
|
|
2306
|
+
if code is None:
|
|
2307
|
+
return None, Error(
|
|
2308
|
+
cls.parsed.node,
|
|
2309
|
+
f"The implementation is missing for the JSON serialization "
|
|
2310
|
+
f"of {cls.name!r}: {implementation_key}",
|
|
2311
|
+
)
|
|
2312
|
+
return code, None
|
|
2313
|
+
|
|
2314
|
+
blocks = [
|
|
2315
|
+
Stripped(
|
|
2316
|
+
"""\
|
|
2317
|
+
nlohmann::json result = nlohmann::json::object();"""
|
|
2318
|
+
)
|
|
2319
|
+
] # type: List[Stripped]
|
|
2320
|
+
|
|
2321
|
+
needs_error = False
|
|
2322
|
+
for prop in cls.properties:
|
|
2323
|
+
type_anno = intermediate.beneath_optional(prop.type_annotation)
|
|
2324
|
+
primitive_type = intermediate.try_primitive_type(type_anno)
|
|
2325
|
+
|
|
2326
|
+
if primitive_type is not None and (
|
|
2327
|
+
primitive_type is intermediate.PrimitiveType.INT
|
|
2328
|
+
):
|
|
2329
|
+
needs_error = True
|
|
2330
|
+
break
|
|
2331
|
+
|
|
2332
|
+
if isinstance(type_anno, intermediate.OurTypeAnnotation) or (
|
|
2333
|
+
isinstance(type_anno, intermediate.ListTypeAnnotation)
|
|
2334
|
+
and isinstance(type_anno.items, intermediate.OurTypeAnnotation)
|
|
2335
|
+
):
|
|
2336
|
+
needs_error = True
|
|
2337
|
+
break
|
|
2338
|
+
|
|
2339
|
+
if needs_error:
|
|
2340
|
+
blocks.append(Stripped("common::optional<SerializationError> error;"))
|
|
2341
|
+
|
|
2342
|
+
for prop in cls.properties:
|
|
2343
|
+
blocks.append(_generate_serialize_property(prop=prop))
|
|
2344
|
+
|
|
2345
|
+
if cls.serialization.with_model_type:
|
|
2346
|
+
model_type_literal = cpp_common.string_literal(naming.json_model_type(cls.name))
|
|
2347
|
+
blocks.append(Stripped(f'result["modelType"] = {model_type_literal};'))
|
|
2348
|
+
|
|
2349
|
+
blocks.append(
|
|
2350
|
+
Stripped(
|
|
2351
|
+
f"""\
|
|
2352
|
+
return std::make_pair<
|
|
2353
|
+
{I}common::optional<nlohmann::json>,
|
|
2354
|
+
{I}common::optional<SerializationError>
|
|
2355
|
+
>(
|
|
2356
|
+
{I}common::make_optional<nlohmann::json>(std::move(result)),
|
|
2357
|
+
{I}common::nullopt
|
|
2358
|
+
);"""
|
|
2359
|
+
)
|
|
2360
|
+
)
|
|
2361
|
+
|
|
2362
|
+
blocks_joined = "\n\n".join(blocks)
|
|
2363
|
+
|
|
2364
|
+
serialize_name = cpp_naming.function_name(Identifier(f"serialize_{cls.name}"))
|
|
2365
|
+
|
|
2366
|
+
interface_name = cpp_naming.interface_name(cls.name)
|
|
2367
|
+
|
|
2368
|
+
return (
|
|
2369
|
+
Stripped(
|
|
2370
|
+
f"""\
|
|
2371
|
+
std::pair<
|
|
2372
|
+
{I}common::optional<nlohmann::json>,
|
|
2373
|
+
{I}common::optional<SerializationError>
|
|
2374
|
+
> {serialize_name}(
|
|
2375
|
+
{I}const types::{interface_name}& that
|
|
2376
|
+
) {{
|
|
2377
|
+
{I}{indent_but_first_line(blocks_joined, I)}
|
|
2378
|
+
}}"""
|
|
2379
|
+
),
|
|
2380
|
+
None,
|
|
2381
|
+
)
|
|
2382
|
+
|
|
2383
|
+
|
|
2384
|
+
def _generate_serialize_iclass_implementation(
|
|
2385
|
+
symbol_table: intermediate.SymbolTable,
|
|
2386
|
+
) -> Stripped:
|
|
2387
|
+
"""Generate the main dispatch function for serializing ``IClass``."""
|
|
2388
|
+
case_blocks = [] # type: List[Stripped]
|
|
2389
|
+
for cls in symbol_table.concrete_classes:
|
|
2390
|
+
serialize_name = cpp_naming.function_name(Identifier(f"serialize_{cls.name}"))
|
|
2391
|
+
|
|
2392
|
+
model_type_literal = cpp_naming.enum_literal_name(cls.name)
|
|
2393
|
+
model_type_enum = cpp_naming.enum_name(Identifier("Model_type"))
|
|
2394
|
+
|
|
2395
|
+
interface_name = cpp_naming.interface_name(cls.name)
|
|
2396
|
+
|
|
2397
|
+
case_blocks.append(
|
|
2398
|
+
Stripped(
|
|
2399
|
+
f"""\
|
|
2400
|
+
case types::{model_type_enum}::{model_type_literal}:
|
|
2401
|
+
{I}return {serialize_name}(
|
|
2402
|
+
{II}dynamic_cast<const types::{interface_name}&>(that)
|
|
2403
|
+
{I});"""
|
|
2404
|
+
)
|
|
2405
|
+
)
|
|
2406
|
+
|
|
2407
|
+
case_blocks.append(
|
|
2408
|
+
Stripped(
|
|
2409
|
+
f"""\
|
|
2410
|
+
default: {{
|
|
2411
|
+
{I}std::string message = common::Concat(
|
|
2412
|
+
{II}"Unexpected model type: ",
|
|
2413
|
+
{II}std::to_string(
|
|
2414
|
+
{III}static_cast<std::uint32_t>(
|
|
2415
|
+
{IIII}that.model_type()
|
|
2416
|
+
{III})
|
|
2417
|
+
{II})
|
|
2418
|
+
{I});
|
|
2419
|
+
|
|
2420
|
+
{I}throw std::invalid_argument(message);
|
|
2421
|
+
}}"""
|
|
2422
|
+
)
|
|
2423
|
+
)
|
|
2424
|
+
|
|
2425
|
+
case_blocks_joined = "\n".join(case_blocks)
|
|
2426
|
+
|
|
2427
|
+
return Stripped(
|
|
2428
|
+
f"""\
|
|
2429
|
+
std::pair<
|
|
2430
|
+
{I}common::optional<nlohmann::json>,
|
|
2431
|
+
{I}common::optional<SerializationError>
|
|
2432
|
+
> SerializeIClass(
|
|
2433
|
+
{I}const types::IClass& that
|
|
2434
|
+
) {{
|
|
2435
|
+
{I}switch (that.model_type()) {{
|
|
2436
|
+
{II}{indent_but_first_line(case_blocks_joined, II)}
|
|
2437
|
+
{I}}};
|
|
2438
|
+
}}"""
|
|
2439
|
+
)
|
|
2440
|
+
|
|
2441
|
+
|
|
2442
|
+
def _generate_serialize_implementation() -> Stripped:
|
|
2443
|
+
"""Generate the main serialization function."""
|
|
2444
|
+
return Stripped(
|
|
2445
|
+
f"""\
|
|
2446
|
+
nlohmann::json Serialize(
|
|
2447
|
+
{I}const types::IClass& that
|
|
2448
|
+
) {{
|
|
2449
|
+
{I}common::optional<nlohmann::json> result;
|
|
2450
|
+
{I}common::optional<SerializationError> error;
|
|
2451
|
+
|
|
2452
|
+
{I}std::tie(
|
|
2453
|
+
{II}result,
|
|
2454
|
+
{II}error
|
|
2455
|
+
{I}) = SerializeIClass(that);
|
|
2456
|
+
|
|
2457
|
+
{I}if (error.has_value()) {{
|
|
2458
|
+
{II}throw SerializationException(
|
|
2459
|
+
{III}std::move(error->cause),
|
|
2460
|
+
{III}std::move(error->path)
|
|
2461
|
+
{II});
|
|
2462
|
+
{I}}}
|
|
2463
|
+
|
|
2464
|
+
{I}return std::move(*result);
|
|
2465
|
+
}}"""
|
|
2466
|
+
)
|
|
2467
|
+
|
|
2468
|
+
|
|
2469
|
+
# fmt: off
|
|
2470
|
+
@ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
|
|
2471
|
+
@ensure(
|
|
2472
|
+
lambda result:
|
|
2473
|
+
not (result[0] is not None) or result[0].endswith('\n'),
|
|
2474
|
+
"Trailing newline mandatory for valid end-of-files"
|
|
2475
|
+
)
|
|
2476
|
+
# fmt: on
|
|
2477
|
+
def generate_implementation(
|
|
2478
|
+
symbol_table: intermediate.SymbolTable,
|
|
2479
|
+
spec_impls: specific_implementations.SpecificImplementations,
|
|
2480
|
+
library_namespace: Stripped,
|
|
2481
|
+
) -> Tuple[Optional[str], Optional[List[Error]]]:
|
|
2482
|
+
"""Generate the C++ implementation of the de/serialization functions."""
|
|
2483
|
+
namespace = Stripped(f"{library_namespace}::{cpp_common.JSONIZATION_NAMESPACE}")
|
|
2484
|
+
|
|
2485
|
+
include_prefix_path = cpp_common.generate_include_prefix_path(library_namespace)
|
|
2486
|
+
|
|
2487
|
+
blocks = [
|
|
2488
|
+
cpp_common.WARNING,
|
|
2489
|
+
Stripped(
|
|
2490
|
+
f"""\
|
|
2491
|
+
#include "{include_prefix_path}/jsonization.hpp"
|
|
2492
|
+
#include "{include_prefix_path}/stringification.hpp"
|
|
2493
|
+
#include "{include_prefix_path}/wstringification.hpp"
|
|
2494
|
+
|
|
2495
|
+
#pragma warning(push, 0)
|
|
2496
|
+
#include <functional>
|
|
2497
|
+
#include <map>
|
|
2498
|
+
#include <set>
|
|
2499
|
+
#include <sstream>
|
|
2500
|
+
#pragma warning(pop)"""
|
|
2501
|
+
),
|
|
2502
|
+
cpp_common.generate_namespace_opening(namespace),
|
|
2503
|
+
*_generate_property_segment_implementation(),
|
|
2504
|
+
*_generate_index_segment_implementation(),
|
|
2505
|
+
*_generate_path_implementation(),
|
|
2506
|
+
Stripped("// region De-serialization"),
|
|
2507
|
+
*_generate_deserialization_error_implementation(),
|
|
2508
|
+
_generate_deserialize_bool(),
|
|
2509
|
+
_generate_deserialize_int(),
|
|
2510
|
+
_generate_deserialize_float(),
|
|
2511
|
+
_generate_deserialize_str(),
|
|
2512
|
+
_generate_deserialize_bytearray(),
|
|
2513
|
+
_generate_get_model_type(),
|
|
2514
|
+
]
|
|
2515
|
+
|
|
2516
|
+
for cls in symbol_table.classes:
|
|
2517
|
+
if isinstance(cls, intermediate.ConcreteClass):
|
|
2518
|
+
blocks.append(
|
|
2519
|
+
_generate_concretely_deserialize_definition(
|
|
2520
|
+
cls=cls,
|
|
2521
|
+
)
|
|
2522
|
+
)
|
|
2523
|
+
|
|
2524
|
+
if len(cls.concrete_descendants) > 0:
|
|
2525
|
+
blocks.append(_generate_dispatch_deserialize_definition(cls=cls))
|
|
2526
|
+
|
|
2527
|
+
errors = [] # type: List[Error]
|
|
2528
|
+
|
|
2529
|
+
for cls in symbol_table.classes:
|
|
2530
|
+
if isinstance(cls, intermediate.ConcreteClass):
|
|
2531
|
+
deserialize_block, error = _generate_concretely_deserialize_implementation(
|
|
2532
|
+
cls=cls,
|
|
2533
|
+
spec_impls=spec_impls,
|
|
2534
|
+
)
|
|
2535
|
+
if error is not None:
|
|
2536
|
+
errors.append(error)
|
|
2537
|
+
continue
|
|
2538
|
+
|
|
2539
|
+
assert deserialize_block is not None
|
|
2540
|
+
blocks.append(deserialize_block)
|
|
2541
|
+
|
|
2542
|
+
if len(cls.concrete_descendants) > 0:
|
|
2543
|
+
deserialize_dispatch_blocks = _generate_dispatch_deserialize_implementation(
|
|
2544
|
+
cls=cls
|
|
2545
|
+
)
|
|
2546
|
+
blocks.extend(deserialize_dispatch_blocks)
|
|
2547
|
+
|
|
2548
|
+
for cls in symbol_table.classes:
|
|
2549
|
+
blocks.append(_generate_deserialization_implementation(cls=cls))
|
|
2550
|
+
|
|
2551
|
+
blocks.extend(
|
|
2552
|
+
[
|
|
2553
|
+
Stripped("// endregion De-serialization"),
|
|
2554
|
+
Stripped("// region Serialization"),
|
|
2555
|
+
Stripped(
|
|
2556
|
+
f"""\
|
|
2557
|
+
/**
|
|
2558
|
+
* \\brief Represent a serialization error.
|
|
2559
|
+
*
|
|
2560
|
+
* We use this error internally to avoid unnecessary stack unwinding,
|
|
2561
|
+
* but throw the \\ref SerializationException at the final site of
|
|
2562
|
+
* the serialization for the user.
|
|
2563
|
+
*/
|
|
2564
|
+
struct SerializationError {{
|
|
2565
|
+
{I}/**
|
|
2566
|
+
{I} * Human-readable description of the error
|
|
2567
|
+
{I} */
|
|
2568
|
+
{I}std::wstring cause;
|
|
2569
|
+
|
|
2570
|
+
{I}/**
|
|
2571
|
+
{I} * Path to the value that caused the error
|
|
2572
|
+
{I} */
|
|
2573
|
+
{I}iteration::Path path;
|
|
2574
|
+
|
|
2575
|
+
{I}explicit SerializationError(
|
|
2576
|
+
{II}std::wstring a_cause
|
|
2577
|
+
{I}) : cause(std::move(a_cause)) {{
|
|
2578
|
+
{II}// Intentionally empty.
|
|
2579
|
+
{I}}}
|
|
2580
|
+
}}; // struct SerializationError"""
|
|
2581
|
+
),
|
|
2582
|
+
*_generate_serialization_exception_implementation(),
|
|
2583
|
+
_generate_serialize_int(),
|
|
2584
|
+
_generate_serialize_str(),
|
|
2585
|
+
_generate_serialize_bytearray(),
|
|
2586
|
+
_generate_serialize_iclass_definition(),
|
|
2587
|
+
]
|
|
2588
|
+
)
|
|
2589
|
+
|
|
2590
|
+
for cls in symbol_table.concrete_classes:
|
|
2591
|
+
serialize_block, error = _generate_serialize_cls(cls=cls, spec_impls=spec_impls)
|
|
2592
|
+
if error is not None:
|
|
2593
|
+
errors.append(error)
|
|
2594
|
+
else:
|
|
2595
|
+
assert serialize_block is not None
|
|
2596
|
+
blocks.append(serialize_block)
|
|
2597
|
+
|
|
2598
|
+
blocks.append(_generate_serialize_iclass_implementation(symbol_table=symbol_table))
|
|
2599
|
+
|
|
2600
|
+
blocks.append(_generate_serialize_implementation())
|
|
2601
|
+
|
|
2602
|
+
blocks.extend(
|
|
2603
|
+
[
|
|
2604
|
+
Stripped("// endregion Serialization"),
|
|
2605
|
+
cpp_common.generate_namespace_closing(namespace),
|
|
2606
|
+
cpp_common.WARNING,
|
|
2607
|
+
]
|
|
2608
|
+
)
|
|
2609
|
+
|
|
2610
|
+
writer = io.StringIO()
|
|
2611
|
+
for i, block in enumerate(blocks):
|
|
2612
|
+
if i > 0:
|
|
2613
|
+
writer.write("\n\n")
|
|
2614
|
+
|
|
2615
|
+
writer.write(block)
|
|
2616
|
+
|
|
2617
|
+
writer.write("\n")
|
|
2618
|
+
|
|
2619
|
+
return writer.getvalue(), None
|