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,985 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Transpile the regular expressions to instructions of a Virtual Machine.
|
|
3
|
+
|
|
4
|
+
The implementation in the standard library has exponential time complexity, so it was
|
|
5
|
+
a major blocker for most of the practical inputs. For example, see this bug report:
|
|
6
|
+
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93502
|
|
7
|
+
|
|
8
|
+
The virtual machine is based on Ken Thompson's approach published in:
|
|
9
|
+
Thompson, K., "Regular expression search algorithm", ACM 11(6) (June 1968)
|
|
10
|
+
|
|
11
|
+
We followed a very clear and concise blog post which described it in detail:
|
|
12
|
+
https://swtch.com/~rsc/regexp/regexp2.html
|
|
13
|
+
|
|
14
|
+
The ideas for additional instructions were taken from:
|
|
15
|
+
https://www.codeproject.com/Articles/5256833/Regex-as-a-Tiny-Threaded-Virtual-Machine
|
|
16
|
+
"""
|
|
17
|
+
import dataclasses
|
|
18
|
+
import io
|
|
19
|
+
from typing import (
|
|
20
|
+
Final,
|
|
21
|
+
cast,
|
|
22
|
+
List,
|
|
23
|
+
Optional,
|
|
24
|
+
Union,
|
|
25
|
+
Tuple,
|
|
26
|
+
TextIO,
|
|
27
|
+
MutableMapping,
|
|
28
|
+
Sequence,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
from icontract import require
|
|
32
|
+
|
|
33
|
+
from aas_core_codegen.common import assert_never, pairwise
|
|
34
|
+
from aas_core_codegen.parse import retree as parse_retree, tree as parse_tree
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Character(str):
|
|
38
|
+
"""Represent a single character."""
|
|
39
|
+
|
|
40
|
+
@require(lambda text: len(text) == 1)
|
|
41
|
+
def __new__(cls, text: str) -> "Character":
|
|
42
|
+
return cast(Character, text)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclasses.dataclass
|
|
46
|
+
class InstructionChar:
|
|
47
|
+
"""Match a single character."""
|
|
48
|
+
|
|
49
|
+
character: Character
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Range:
|
|
53
|
+
"""Define a character range."""
|
|
54
|
+
|
|
55
|
+
first: Final[Character]
|
|
56
|
+
last: Final[Character]
|
|
57
|
+
|
|
58
|
+
# fmt: off
|
|
59
|
+
@require(
|
|
60
|
+
lambda first, last: ord(first) <= ord(last),
|
|
61
|
+
"Range boundaries must be sorted."
|
|
62
|
+
)
|
|
63
|
+
# fmt: on
|
|
64
|
+
def __init__(self, first: Character, last: Character) -> None:
|
|
65
|
+
"""Initialize with the given values."""
|
|
66
|
+
self.first = first
|
|
67
|
+
self.last = last
|
|
68
|
+
|
|
69
|
+
def __str__(self) -> str:
|
|
70
|
+
return f"{self.__class__.__name__}({self.first!r}, {self.last!r})"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def check_ranges_sorted_and_non_overlapping(ranges: Sequence[Range]) -> Optional[str]:
|
|
74
|
+
"""
|
|
75
|
+
Check that the ranges' boundaries are sorted and non-overlapping.
|
|
76
|
+
|
|
77
|
+
If there are no errors, return ``None``. Otherwise, return a message explaining
|
|
78
|
+
what precisely was not satisfied.
|
|
79
|
+
"""
|
|
80
|
+
for this_range, next_range in pairwise(ranges):
|
|
81
|
+
if ord(this_range.first) >= ord(next_range.last):
|
|
82
|
+
return (
|
|
83
|
+
f"The range {this_range} and its next range {next_range} "
|
|
84
|
+
f"are not in sorted order."
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if ord(this_range.last) >= ord(next_range.first):
|
|
88
|
+
return f"The range {this_range} and its next range {next_range} overlap."
|
|
89
|
+
|
|
90
|
+
return None
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class InstructionSet:
|
|
94
|
+
"""Match a set of characters."""
|
|
95
|
+
|
|
96
|
+
ranges: Final[Sequence[Range]]
|
|
97
|
+
|
|
98
|
+
@require(lambda ranges: check_ranges_sorted_and_non_overlapping(ranges) is None)
|
|
99
|
+
def __init__(self, ranges: Sequence[Range]) -> None:
|
|
100
|
+
"""Initialize with the given values."""
|
|
101
|
+
self.ranges = ranges
|
|
102
|
+
|
|
103
|
+
def __str__(self) -> str:
|
|
104
|
+
return f"{self.__class__.__name__}({self.ranges!r})"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class InstructionNotSet:
|
|
108
|
+
"""Match an out-of-set character."""
|
|
109
|
+
|
|
110
|
+
ranges: Final[Sequence[Range]]
|
|
111
|
+
|
|
112
|
+
@require(lambda ranges: check_ranges_sorted_and_non_overlapping(ranges) is None)
|
|
113
|
+
def __init__(self, ranges: Sequence[Range]) -> None:
|
|
114
|
+
"""Initialize with the given values."""
|
|
115
|
+
self.ranges = ranges
|
|
116
|
+
|
|
117
|
+
def __str__(self) -> str:
|
|
118
|
+
return f"{self.__class__.__name__}({self.ranges!r})"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@dataclasses.dataclass
|
|
122
|
+
class InstructionAny:
|
|
123
|
+
"""Match any character."""
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@dataclasses.dataclass
|
|
127
|
+
class InstructionMatch:
|
|
128
|
+
"""Stop the thread and signal that we found a match."""
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@dataclasses.dataclass
|
|
132
|
+
class InstructionJump:
|
|
133
|
+
"""Jump to the indicated position in the program."""
|
|
134
|
+
|
|
135
|
+
target: int
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@dataclasses.dataclass
|
|
139
|
+
class InstructionSplit:
|
|
140
|
+
"""Split the program in two threads, both jumping to different locations."""
|
|
141
|
+
|
|
142
|
+
first_target: int
|
|
143
|
+
second_target: int
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@dataclasses.dataclass
|
|
147
|
+
class InstructionEnd:
|
|
148
|
+
"""Match the end-of-input."""
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@dataclasses.dataclass
|
|
152
|
+
class _InstructionNoop:
|
|
153
|
+
"""
|
|
154
|
+
Represent a no-operation instruction which does nothing.
|
|
155
|
+
|
|
156
|
+
This is used only as a place-holder during the translation.
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
Instruction = Union[
|
|
161
|
+
InstructionChar,
|
|
162
|
+
InstructionSet,
|
|
163
|
+
InstructionNotSet,
|
|
164
|
+
InstructionAny,
|
|
165
|
+
InstructionMatch,
|
|
166
|
+
InstructionJump,
|
|
167
|
+
InstructionSplit,
|
|
168
|
+
InstructionEnd,
|
|
169
|
+
]
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
# NOTE (mristin):
|
|
173
|
+
# The classes ``_Leaf`` and ``_Node`` correspond to the translation phase, while
|
|
174
|
+
# the classes ``Leaf`` and ``Node`` are used to represent the final result.
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@dataclasses.dataclass
|
|
178
|
+
class _Leaf:
|
|
179
|
+
"""Represent a leaf node in the nested instruction tree during compilation."""
|
|
180
|
+
|
|
181
|
+
instruction: Union[Instruction, _InstructionNoop]
|
|
182
|
+
label: Optional[int] = None
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@dataclasses.dataclass
|
|
186
|
+
class _Node:
|
|
187
|
+
"""Represent nested instructions during compilation."""
|
|
188
|
+
|
|
189
|
+
re_node: parse_retree.Node
|
|
190
|
+
children: List["_NodeOrLeaf"]
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
_NodeOrLeaf = Union[_Node, _Leaf]
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@dataclasses.dataclass
|
|
197
|
+
class Leaf:
|
|
198
|
+
"""Represent a leaf node in the nested instruction tree."""
|
|
199
|
+
|
|
200
|
+
instruction: Instruction
|
|
201
|
+
label: Optional[int] = None
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@dataclasses.dataclass
|
|
205
|
+
class Node:
|
|
206
|
+
"""Represent nested instructions related to a part of the regular expression."""
|
|
207
|
+
|
|
208
|
+
re_node: parse_retree.Node
|
|
209
|
+
children: List["NodeOrLeaf"]
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
NodeOrLeaf = Union[Node, Leaf]
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class _CheckForFormattedValue(parse_retree.PassThroughVisitor):
|
|
216
|
+
"""Check that no ``FormattedValue`` is contained in a pattern."""
|
|
217
|
+
|
|
218
|
+
def __init__(self) -> None:
|
|
219
|
+
self.has_formatted_value = False
|
|
220
|
+
|
|
221
|
+
def visit_term(self, node: parse_retree.Term) -> None:
|
|
222
|
+
if isinstance(node.value, parse_tree.FormattedValue):
|
|
223
|
+
self.has_formatted_value = True
|
|
224
|
+
|
|
225
|
+
super().visit_term(node)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class _CheckForNonGreedyQuantifiers(parse_retree.PassThroughVisitor):
|
|
229
|
+
"""Check for presence of non-greedy quantifiers in a pattern."""
|
|
230
|
+
|
|
231
|
+
def __init__(self) -> None:
|
|
232
|
+
self.has_non_greedy_quantifiers = False
|
|
233
|
+
|
|
234
|
+
def visit_quantifier(self, node: parse_retree.Quantifier) -> None:
|
|
235
|
+
if node.non_greedy:
|
|
236
|
+
self.has_non_greedy_quantifiers = True
|
|
237
|
+
|
|
238
|
+
super().visit_quantifier(node)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class _RegexRenderer(parse_retree.Renderer):
|
|
242
|
+
"""
|
|
243
|
+
Render regex patterns for readable comments.
|
|
244
|
+
|
|
245
|
+
In contrast to :py:class:`parse_retree.Renderer`, we also render
|
|
246
|
+
the :py:class:`parse_retree.Char` as we need to cover the granularity of a single
|
|
247
|
+
character in this module.
|
|
248
|
+
"""
|
|
249
|
+
|
|
250
|
+
def transform_char(
|
|
251
|
+
self, node: parse_retree.Char
|
|
252
|
+
) -> List[Union[str, parse_tree.FormattedValue]]:
|
|
253
|
+
return self.char_to_str_and_escape_or_encode_if_necessary(
|
|
254
|
+
node=node, escaping=parse_retree.Renderer._ESCAPING_IN_CHARACTER_LITERALS
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
_REGEX_RENDERER = _RegexRenderer()
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def _render_re_node(re_node: parse_retree.Node) -> str:
|
|
262
|
+
"""Render the pattern as a string for comments."""
|
|
263
|
+
parts = _REGEX_RENDERER.transform(re_node)
|
|
264
|
+
assert all(
|
|
265
|
+
isinstance(part, str) for part in parts
|
|
266
|
+
), f"Expected all rendered parts to be strings, but got: {parts}"
|
|
267
|
+
|
|
268
|
+
return "".join(parts) # type: ignore
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class _Translator(parse_retree.Transformer[_Node]):
|
|
272
|
+
"""Translate the regular expression to nested instructions."""
|
|
273
|
+
|
|
274
|
+
def __init__(self) -> None:
|
|
275
|
+
self._next_label = 0
|
|
276
|
+
|
|
277
|
+
def _obtain_label(self) -> int:
|
|
278
|
+
"""
|
|
279
|
+
Return the current next label, and increment it for the next call.
|
|
280
|
+
|
|
281
|
+
Do not fiddle with :py:attr:`_next_label` yourself; use this function.
|
|
282
|
+
"""
|
|
283
|
+
result = self._next_label
|
|
284
|
+
self._next_label += 1
|
|
285
|
+
return result
|
|
286
|
+
|
|
287
|
+
def transform_union_expr(self, node: parse_retree.UnionExpr) -> _Node:
|
|
288
|
+
if len(node.uniates) == 0:
|
|
289
|
+
return _Node(re_node=node, children=[_Leaf(instruction=_InstructionNoop())])
|
|
290
|
+
elif len(node.uniates) == 1:
|
|
291
|
+
return self.transform(node.uniates[0])
|
|
292
|
+
else:
|
|
293
|
+
pass
|
|
294
|
+
|
|
295
|
+
children = [] # type: List[_NodeOrLeaf]
|
|
296
|
+
|
|
297
|
+
final_label = self._obtain_label()
|
|
298
|
+
|
|
299
|
+
for i, uniate in enumerate(node.uniates):
|
|
300
|
+
if i < len(node.uniates) - 1:
|
|
301
|
+
l0 = self._obtain_label()
|
|
302
|
+
l1 = self._obtain_label()
|
|
303
|
+
|
|
304
|
+
children.append(
|
|
305
|
+
_Leaf(InstructionSplit(first_target=l0, second_target=l1))
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
children.append(_Leaf(_InstructionNoop(), label=l0))
|
|
309
|
+
|
|
310
|
+
children.append(self.transform(uniate))
|
|
311
|
+
|
|
312
|
+
children.append(_Leaf(InstructionJump(target=final_label)))
|
|
313
|
+
|
|
314
|
+
children.append(_Leaf(_InstructionNoop(), label=l1))
|
|
315
|
+
else:
|
|
316
|
+
children.append(self.transform(uniate))
|
|
317
|
+
|
|
318
|
+
children.append(_Leaf(_InstructionNoop(), label=final_label))
|
|
319
|
+
|
|
320
|
+
return _Node(re_node=node, children=children)
|
|
321
|
+
|
|
322
|
+
def transform_concatenation(self, node: parse_retree.Concatenation) -> _Node:
|
|
323
|
+
if len(node.concatenants) == 0:
|
|
324
|
+
return _Node(re_node=node, children=[_Leaf(instruction=_InstructionNoop())])
|
|
325
|
+
|
|
326
|
+
elif len(node.concatenants) == 1:
|
|
327
|
+
return self.transform(node=node.concatenants[0])
|
|
328
|
+
|
|
329
|
+
else:
|
|
330
|
+
return _Node(
|
|
331
|
+
re_node=node,
|
|
332
|
+
children=[
|
|
333
|
+
self.transform(concatenant) for concatenant in node.concatenants
|
|
334
|
+
],
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
def transform_symbol(self, node: parse_retree.Symbol) -> _Node:
|
|
338
|
+
if node.kind is parse_retree.SymbolKind.START:
|
|
339
|
+
raise AssertionError(
|
|
340
|
+
"We expect that the caller skipped the start anchor "
|
|
341
|
+
"as we always expect the patterns to be anchored at start, and there "
|
|
342
|
+
"is no matching to be done against the start anchor. We decided "
|
|
343
|
+
"against introduction of a no-op instruction since that only eats up "
|
|
344
|
+
"resources, which we can avoid with a bit of smartness in "
|
|
345
|
+
"the transpilation phase."
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
elif node.kind is parse_retree.SymbolKind.END:
|
|
349
|
+
return _Node(re_node=node, children=[_Leaf(instruction=InstructionEnd())])
|
|
350
|
+
|
|
351
|
+
elif node.kind is parse_retree.SymbolKind.DOT:
|
|
352
|
+
return _Node(
|
|
353
|
+
re_node=node,
|
|
354
|
+
children=[_Leaf(instruction=InstructionAny())],
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
else:
|
|
358
|
+
assert_never(node.kind)
|
|
359
|
+
|
|
360
|
+
def transform_term(self, node: parse_retree.Term) -> _Node:
|
|
361
|
+
assert not isinstance(node.value, parse_tree.FormattedValue), (
|
|
362
|
+
"Unexpected formatted value in the regular expression to be "
|
|
363
|
+
"transformed into a program for Regex Virtual Machine. "
|
|
364
|
+
"This should have been checked before. "
|
|
365
|
+
f"The formatted value is: {parse_tree.dump(node.value)}"
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
if node.quantifier is not None:
|
|
369
|
+
if node.quantifier.non_greedy:
|
|
370
|
+
raise AssertionError(
|
|
371
|
+
"(mristin, 2024-06-04) Only non-greedy quantifiers are currently "
|
|
372
|
+
"translated to a program for a RegEx virtual machine. We did not "
|
|
373
|
+
"cover non-greedy quantifiers for simplicity, as we currently have "
|
|
374
|
+
"no meta-model where they are required. The presence of non-greedy "
|
|
375
|
+
"quantifiers should have been caught before, as we explicitly "
|
|
376
|
+
"check for them when transpiling a meta-model. Please report "
|
|
377
|
+
"this exception to the developers as a bug."
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
if node.quantifier.minimum == 1 and node.quantifier.maximum == 1:
|
|
381
|
+
return self.transform(node.value)
|
|
382
|
+
|
|
383
|
+
children = [] # type: List[_NodeOrLeaf]
|
|
384
|
+
|
|
385
|
+
if node.quantifier.maximum is not None:
|
|
386
|
+
for _ in range(0, node.quantifier.minimum):
|
|
387
|
+
children.append(self.transform(node.value))
|
|
388
|
+
|
|
389
|
+
optional_count = node.quantifier.maximum - node.quantifier.minimum
|
|
390
|
+
if optional_count > 0:
|
|
391
|
+
final_label = self._obtain_label()
|
|
392
|
+
|
|
393
|
+
for _ in range(optional_count):
|
|
394
|
+
l1 = self._obtain_label()
|
|
395
|
+
children.append(
|
|
396
|
+
_Leaf(
|
|
397
|
+
InstructionSplit(
|
|
398
|
+
first_target=l1, second_target=final_label
|
|
399
|
+
)
|
|
400
|
+
)
|
|
401
|
+
)
|
|
402
|
+
children.append(_Leaf(_InstructionNoop(), label=l1))
|
|
403
|
+
children.append(self.transform(node.value))
|
|
404
|
+
|
|
405
|
+
children.append(_Leaf(_InstructionNoop(), label=final_label))
|
|
406
|
+
else:
|
|
407
|
+
if node.quantifier.minimum == 0:
|
|
408
|
+
l1 = self._obtain_label()
|
|
409
|
+
l2 = self._obtain_label()
|
|
410
|
+
final_label = self._obtain_label()
|
|
411
|
+
|
|
412
|
+
children.append(
|
|
413
|
+
_Leaf(
|
|
414
|
+
InstructionSplit(
|
|
415
|
+
first_target=l2, second_target=final_label
|
|
416
|
+
),
|
|
417
|
+
label=l1,
|
|
418
|
+
)
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
children.append(_Leaf(_InstructionNoop(), label=l2))
|
|
422
|
+
children.append(self.transform(node.value))
|
|
423
|
+
children.append(_Leaf(InstructionJump(target=l1)))
|
|
424
|
+
|
|
425
|
+
children.append(_Leaf(_InstructionNoop(), label=final_label))
|
|
426
|
+
|
|
427
|
+
else:
|
|
428
|
+
# NOTE (mristin):
|
|
429
|
+
# The last mandatory repetition will be used for the unbounded loop.
|
|
430
|
+
for _ in range(0, node.quantifier.minimum - 1):
|
|
431
|
+
children.append(self.transform(node.value))
|
|
432
|
+
|
|
433
|
+
l1 = self._obtain_label()
|
|
434
|
+
final_label = self._obtain_label()
|
|
435
|
+
|
|
436
|
+
children.append(_Leaf(_InstructionNoop(), label=l1))
|
|
437
|
+
children.append(self.transform(node.value))
|
|
438
|
+
children.append(
|
|
439
|
+
_Leaf(
|
|
440
|
+
InstructionSplit(first_target=l1, second_target=final_label)
|
|
441
|
+
)
|
|
442
|
+
)
|
|
443
|
+
children.append(_Leaf(_InstructionNoop(), label=final_label))
|
|
444
|
+
|
|
445
|
+
return _Node(re_node=node, children=children)
|
|
446
|
+
|
|
447
|
+
else:
|
|
448
|
+
return self.transform(node.value)
|
|
449
|
+
|
|
450
|
+
def transform_group(self, node: parse_retree.Group) -> _Node:
|
|
451
|
+
return self.transform(node.union)
|
|
452
|
+
|
|
453
|
+
def transform_char(self, node: parse_retree.Char) -> _Node:
|
|
454
|
+
return _Node(
|
|
455
|
+
re_node=node,
|
|
456
|
+
children=[
|
|
457
|
+
_Leaf(instruction=InstructionChar(character=Character(node.character)))
|
|
458
|
+
],
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
def transform_quantifier(self, node: parse_retree.Quantifier) -> _Node:
|
|
462
|
+
raise AssertionError(
|
|
463
|
+
f"Expected the quantifier to be already handled "
|
|
464
|
+
f"in {_Translator.transform_term.__name__}. We should have never gotten "
|
|
465
|
+
f"here."
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
def transform_char_set(self, node: parse_retree.CharSet) -> _Node:
|
|
469
|
+
ranges = [
|
|
470
|
+
Range(
|
|
471
|
+
first=Character(re_range.start.character),
|
|
472
|
+
last=(
|
|
473
|
+
Character(re_range.end.character)
|
|
474
|
+
if re_range.end is not None
|
|
475
|
+
else Character(re_range.start.character)
|
|
476
|
+
),
|
|
477
|
+
)
|
|
478
|
+
for re_range in node.ranges
|
|
479
|
+
]
|
|
480
|
+
|
|
481
|
+
ranges.sort(key=lambda rng: rng.first)
|
|
482
|
+
|
|
483
|
+
if node.complementing:
|
|
484
|
+
return _Node(
|
|
485
|
+
re_node=node,
|
|
486
|
+
children=[_Leaf(instruction=InstructionNotSet(ranges=ranges))],
|
|
487
|
+
)
|
|
488
|
+
else:
|
|
489
|
+
return _Node(
|
|
490
|
+
re_node=node,
|
|
491
|
+
children=[_Leaf(instruction=InstructionSet(ranges=ranges))],
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
def transform_range(self, node: parse_retree.Range) -> _Node:
|
|
495
|
+
raise AssertionError(
|
|
496
|
+
"Expected to handle a regex range within the character set"
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
def transform_regex(self, node: parse_retree.Regex) -> _Node:
|
|
500
|
+
non_anchored_exception_message = (
|
|
501
|
+
"(mristin, 2024-05-31): We expect all the patterns which need "
|
|
502
|
+
"to be transpiled to instructions of the RegEx virtual machine "
|
|
503
|
+
"to be anchored at the start (``^``) and at the end (``$``). Please "
|
|
504
|
+
"consider re-writing your pattern with putting a prefix ``^.*`` if you "
|
|
505
|
+
"want to match an arbitrary prefix, and a suffix ``.*$`` if you want to "
|
|
506
|
+
"match an arbitrary suffix. "
|
|
507
|
+
"If you really need this feature, please contact the developers. "
|
|
508
|
+
f"The regular expression was: {_render_re_node(node)}"
|
|
509
|
+
)
|
|
510
|
+
|
|
511
|
+
if len(node.union.uniates) == 0 or len(node.union.uniates[0].concatenants) == 0:
|
|
512
|
+
raise NotImplementedError(non_anchored_exception_message)
|
|
513
|
+
|
|
514
|
+
first_term = node.union.uniates[0].concatenants[0]
|
|
515
|
+
last_term = node.union.uniates[0].concatenants[-1]
|
|
516
|
+
|
|
517
|
+
first_symbol_is_start = isinstance(first_term.value, parse_retree.Symbol) and (
|
|
518
|
+
first_term.value.kind is parse_retree.SymbolKind.START
|
|
519
|
+
)
|
|
520
|
+
last_symbol_is_end = isinstance(last_term.value, parse_retree.Symbol) and (
|
|
521
|
+
last_term.value.kind is parse_retree.SymbolKind.END
|
|
522
|
+
)
|
|
523
|
+
|
|
524
|
+
if (
|
|
525
|
+
len(node.union.uniates) != 1
|
|
526
|
+
or not first_symbol_is_start
|
|
527
|
+
or not last_symbol_is_end
|
|
528
|
+
):
|
|
529
|
+
parts = [non_anchored_exception_message]
|
|
530
|
+
if len(node.union.uniates) > 1:
|
|
531
|
+
parts.append(
|
|
532
|
+
"Expected no alternation in the root group of "
|
|
533
|
+
"the pattern (only concatenation), but the pattern starts "
|
|
534
|
+
"with an alternation. You can not properly anchor "
|
|
535
|
+
"with an alternation."
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
if not first_symbol_is_start:
|
|
539
|
+
parts.append(
|
|
540
|
+
f"Expected the first term of the pattern to be a start anchor, "
|
|
541
|
+
f"but it is not. Got: {_render_re_node(first_term)}"
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
if not last_symbol_is_end:
|
|
545
|
+
parts.append(
|
|
546
|
+
f"Expected the last term of the pattern to be an end anchor, "
|
|
547
|
+
f"but it is not. Got: {_render_re_node(last_term)}"
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
raise NotImplementedError("\n\n".join(parts))
|
|
551
|
+
|
|
552
|
+
check_for_formatted_value = _CheckForFormattedValue()
|
|
553
|
+
check_for_formatted_value.visit(node)
|
|
554
|
+
if check_for_formatted_value.has_formatted_value:
|
|
555
|
+
raise AssertionError(
|
|
556
|
+
f"The regex you want to transpile to the instructions of "
|
|
557
|
+
f"a RegEx virtual machine contains a formatted value. "
|
|
558
|
+
f"The formatted values can only be transpiled into code, "
|
|
559
|
+
f"but can not be transpiled into instructions. "
|
|
560
|
+
f"Please check your code logic. "
|
|
561
|
+
f"The pattern was: {parse_retree.dump(node)}"
|
|
562
|
+
)
|
|
563
|
+
|
|
564
|
+
check_for_non_greedy_quantifiers = _CheckForNonGreedyQuantifiers()
|
|
565
|
+
check_for_non_greedy_quantifiers.visit(node)
|
|
566
|
+
if check_for_non_greedy_quantifiers.has_non_greedy_quantifiers:
|
|
567
|
+
raise NotImplementedError(
|
|
568
|
+
"(mristin, 2024-05-31): We did not implement the transpilation of "
|
|
569
|
+
"non-greedy quantifiers to instructions of a RegEx virtual machine "
|
|
570
|
+
"as this is more complex than the transpilation of the greedy ones. "
|
|
571
|
+
"If you need this feature, please contact the developers."
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
assert len(node.union.uniates) == 1, (
|
|
575
|
+
"Only concatenation expected at the root level since we must anchor "
|
|
576
|
+
"at the start and at the end."
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
# region Optimize for arbitrary suffix
|
|
580
|
+
|
|
581
|
+
# NOTE (mristin):
|
|
582
|
+
# We optimize here for the pattern ``.*$`` as we can put an instruction ``Match``
|
|
583
|
+
# just before the arbitrary suffix, and need not the match ``Any`` followed by
|
|
584
|
+
# the ``End``.
|
|
585
|
+
penultimate_term = (
|
|
586
|
+
node.union.uniates[0].concatenants[-2]
|
|
587
|
+
if len(node.union.uniates[0].concatenants) >= 2
|
|
588
|
+
else None
|
|
589
|
+
)
|
|
590
|
+
|
|
591
|
+
assert (
|
|
592
|
+
node.union.uniates[0].concatenants[0] is first_term
|
|
593
|
+
and isinstance(first_term.value, parse_retree.Symbol)
|
|
594
|
+
and first_term.value.kind is parse_retree.SymbolKind.START
|
|
595
|
+
), "Expected the first term to be an anchor at ``^``"
|
|
596
|
+
|
|
597
|
+
assert (
|
|
598
|
+
last_term is node.union.uniates[0].concatenants[-1]
|
|
599
|
+
and isinstance(last_term.value, parse_retree.Symbol)
|
|
600
|
+
and (last_term.value.kind is parse_retree.SymbolKind.END)
|
|
601
|
+
), "Expected the last term to be an anchor at ``$``"
|
|
602
|
+
|
|
603
|
+
if (
|
|
604
|
+
penultimate_term is not None
|
|
605
|
+
and isinstance(penultimate_term.value, parse_retree.Symbol)
|
|
606
|
+
and penultimate_term.value.kind is parse_retree.SymbolKind.DOT
|
|
607
|
+
and penultimate_term.quantifier is not None
|
|
608
|
+
and penultimate_term.quantifier.minimum == 0
|
|
609
|
+
and penultimate_term.quantifier.maximum is None
|
|
610
|
+
):
|
|
611
|
+
# NOTE (mristin):
|
|
612
|
+
# We skip the start anchor as it is not transpiled to an instruction.
|
|
613
|
+
concatenants = node.union.uniates[0].concatenants[1:-2]
|
|
614
|
+
else:
|
|
615
|
+
# NOTE (mristin):
|
|
616
|
+
# We skip the start anchor as it is not transpiled to an instruction.
|
|
617
|
+
concatenants = node.union.uniates[0].concatenants[1:]
|
|
618
|
+
|
|
619
|
+
# endregion
|
|
620
|
+
|
|
621
|
+
children = [] # type: List[_NodeOrLeaf]
|
|
622
|
+
for concatenant in concatenants:
|
|
623
|
+
child = self.transform(concatenant)
|
|
624
|
+
children.append(child)
|
|
625
|
+
|
|
626
|
+
children.append(_Leaf(instruction=InstructionMatch()))
|
|
627
|
+
|
|
628
|
+
return _Node(
|
|
629
|
+
re_node=node,
|
|
630
|
+
children=children,
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
def _recursively_convert_node_for_public(raw_node_or_leaf: _NodeOrLeaf) -> NodeOrLeaf:
|
|
635
|
+
"""
|
|
636
|
+
Convert the post-processed "raw" node into a node for the public use.
|
|
637
|
+
|
|
638
|
+
.. note::
|
|
639
|
+
|
|
640
|
+
All post-processing needs to be performed *before* calling this function.
|
|
641
|
+
This function only copy-converts the nodes into structures to be further
|
|
642
|
+
used by the downstream clients. No post-processing is performed here.
|
|
643
|
+
"""
|
|
644
|
+
if isinstance(raw_node_or_leaf, _Leaf):
|
|
645
|
+
assert not isinstance(
|
|
646
|
+
raw_node_or_leaf.instruction, _InstructionNoop
|
|
647
|
+
), "No no-op instructions expected in public"
|
|
648
|
+
|
|
649
|
+
return Leaf(
|
|
650
|
+
instruction=raw_node_or_leaf.instruction, label=raw_node_or_leaf.label
|
|
651
|
+
)
|
|
652
|
+
|
|
653
|
+
elif isinstance(raw_node_or_leaf, _Node):
|
|
654
|
+
children = [] # type: List[NodeOrLeaf]
|
|
655
|
+
for raw_child in raw_node_or_leaf.children:
|
|
656
|
+
children.append(_recursively_convert_node_for_public(raw_child))
|
|
657
|
+
|
|
658
|
+
return Node(re_node=raw_node_or_leaf.re_node, children=children)
|
|
659
|
+
|
|
660
|
+
else:
|
|
661
|
+
assert_never(raw_node_or_leaf)
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
def _linearize(node: _Node) -> List[_Leaf]:
|
|
665
|
+
"""Make recursively a linear list over all the leaves."""
|
|
666
|
+
lst = [] # type: List[_Leaf]
|
|
667
|
+
for child in node.children:
|
|
668
|
+
if isinstance(child, _Leaf):
|
|
669
|
+
lst.append(child)
|
|
670
|
+
elif isinstance(child, _Node):
|
|
671
|
+
lst.extend(_linearize(child))
|
|
672
|
+
else:
|
|
673
|
+
assert_never(child)
|
|
674
|
+
|
|
675
|
+
return lst
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
def _relabel_in_place(root: _Node) -> None:
|
|
679
|
+
"""
|
|
680
|
+
Re-assign labels according to the indices in a linearized sequence of instructions.
|
|
681
|
+
|
|
682
|
+
We expect that the no-op instructions will be removed, so they are not assigned
|
|
683
|
+
an index.
|
|
684
|
+
"""
|
|
685
|
+
linearized_leaves = _linearize(root)
|
|
686
|
+
|
|
687
|
+
# NOTE (mristin):
|
|
688
|
+
# We index all the leaves except for no-op instructions which are going to be
|
|
689
|
+
# eventually removed. The indices thus correspond to the instructions *after*
|
|
690
|
+
# the no-op instructions are removed.
|
|
691
|
+
|
|
692
|
+
next_index = 0
|
|
693
|
+
|
|
694
|
+
# NOTE (mristin):
|
|
695
|
+
# We map on the ``id(leaf)`` as the leaves are not hashable.
|
|
696
|
+
leaf_to_index = dict() # type: MutableMapping[int, int]
|
|
697
|
+
|
|
698
|
+
for leaf in linearized_leaves:
|
|
699
|
+
if isinstance(leaf.instruction, _InstructionNoop):
|
|
700
|
+
continue
|
|
701
|
+
|
|
702
|
+
leaf_to_index[id(leaf)] = next_index
|
|
703
|
+
next_index += 1
|
|
704
|
+
|
|
705
|
+
# NOTE (mristin):
|
|
706
|
+
# This variable captures the mapping:
|
|
707
|
+
# arbitrary labelling 🠒 labeling according to indices.
|
|
708
|
+
#
|
|
709
|
+
# Only the leaves indicated by new labels will finally have a label at the end.
|
|
710
|
+
old_to_new_label = dict() # type: MutableMapping[int, int]
|
|
711
|
+
|
|
712
|
+
# NOTE (mristin):
|
|
713
|
+
# We iterate in reverse over the leaves so that a single non-no-op instruction
|
|
714
|
+
# can accumulate multiple labels for itself.
|
|
715
|
+
|
|
716
|
+
leaf_after_noop = None # type: Optional[_Leaf]
|
|
717
|
+
for leaf in reversed(linearized_leaves):
|
|
718
|
+
if isinstance(leaf.instruction, _InstructionNoop):
|
|
719
|
+
if leaf.label is not None:
|
|
720
|
+
assert leaf_after_noop is not None, (
|
|
721
|
+
"Expected at least one leaf *after* the no-op instruction. "
|
|
722
|
+
"Since the very last instruction must be a ``match`` instruction, "
|
|
723
|
+
"this must hold, so something obviously went wrong."
|
|
724
|
+
)
|
|
725
|
+
|
|
726
|
+
old_to_new_label[leaf.label] = leaf_to_index[id(leaf_after_noop)]
|
|
727
|
+
else:
|
|
728
|
+
if leaf.label is not None:
|
|
729
|
+
old_to_new_label[leaf.label] = leaf_to_index[id(leaf)]
|
|
730
|
+
|
|
731
|
+
leaf_after_noop = leaf
|
|
732
|
+
|
|
733
|
+
new_label_set = set(old_to_new_label.values())
|
|
734
|
+
|
|
735
|
+
for leaf in linearized_leaves:
|
|
736
|
+
if isinstance(leaf.instruction, _InstructionNoop):
|
|
737
|
+
leaf.label = None
|
|
738
|
+
continue
|
|
739
|
+
|
|
740
|
+
leaf_index = leaf_to_index[id(leaf)]
|
|
741
|
+
|
|
742
|
+
if leaf_index in new_label_set:
|
|
743
|
+
leaf.label = leaf_index
|
|
744
|
+
else:
|
|
745
|
+
leaf.label = None
|
|
746
|
+
|
|
747
|
+
if isinstance(leaf.instruction, InstructionJump):
|
|
748
|
+
leaf.instruction.target = old_to_new_label[leaf.instruction.target]
|
|
749
|
+
|
|
750
|
+
elif isinstance(leaf.instruction, InstructionSplit):
|
|
751
|
+
leaf.instruction.first_target = old_to_new_label[
|
|
752
|
+
leaf.instruction.first_target
|
|
753
|
+
]
|
|
754
|
+
|
|
755
|
+
leaf.instruction.second_target = old_to_new_label[
|
|
756
|
+
leaf.instruction.second_target
|
|
757
|
+
]
|
|
758
|
+
else:
|
|
759
|
+
# NOTE (mristin):
|
|
760
|
+
# Other instruction need not be adapted to the new labels.
|
|
761
|
+
pass
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
def _remove_noop_in_place(node: _Node) -> None:
|
|
765
|
+
"""
|
|
766
|
+
Remove recursively all no-op instructions in place.
|
|
767
|
+
|
|
768
|
+
The no-op instructions are expected to have no labels attached to them.
|
|
769
|
+
"""
|
|
770
|
+
new_children = [] # type: List[_NodeOrLeaf]
|
|
771
|
+
for child in node.children:
|
|
772
|
+
if isinstance(child, _Leaf):
|
|
773
|
+
if isinstance(child.instruction, _InstructionNoop):
|
|
774
|
+
assert child.label is None, (
|
|
775
|
+
f"Expected all no-op leaves to have their labels removed "
|
|
776
|
+
f"before calling {_remove_noop_in_place.__name__}"
|
|
777
|
+
)
|
|
778
|
+
continue
|
|
779
|
+
|
|
780
|
+
elif isinstance(child, _Node):
|
|
781
|
+
_remove_noop_in_place(child)
|
|
782
|
+
|
|
783
|
+
else:
|
|
784
|
+
assert_never(child)
|
|
785
|
+
|
|
786
|
+
new_children.append(child)
|
|
787
|
+
|
|
788
|
+
node.children = new_children
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
def translate(regex: parse_retree.Regex) -> Node:
|
|
792
|
+
"""Translate the regular expression into a program."""
|
|
793
|
+
# NOTE (mristin):
|
|
794
|
+
# We call the nodes "raw" here which still need to be post-processed.
|
|
795
|
+
# The post-processing includes removal of no-ops, re-wiring of the labels *etc.*
|
|
796
|
+
|
|
797
|
+
translator = _Translator()
|
|
798
|
+
raw_root = translator.transform(regex)
|
|
799
|
+
|
|
800
|
+
_relabel_in_place(raw_root)
|
|
801
|
+
_remove_noop_in_place(raw_root)
|
|
802
|
+
|
|
803
|
+
root = _recursively_convert_node_for_public(raw_node_or_leaf=raw_root)
|
|
804
|
+
assert isinstance(root, Node), (
|
|
805
|
+
f"Only node and no leaf expected at the root of the regular expression, "
|
|
806
|
+
f"but got as root: {root}"
|
|
807
|
+
)
|
|
808
|
+
|
|
809
|
+
return root
|
|
810
|
+
|
|
811
|
+
|
|
812
|
+
def _determine_min_and_max_label(node_or_leaf: NodeOrLeaf) -> Optional[Tuple[int, int]]:
|
|
813
|
+
"""
|
|
814
|
+
Iterate recursively over the nodes, and determine the extreme labels in the program.
|
|
815
|
+
|
|
816
|
+
If no node contains a label, return ``None``.
|
|
817
|
+
"""
|
|
818
|
+
if isinstance(node_or_leaf, Leaf):
|
|
819
|
+
if node_or_leaf.label is not None:
|
|
820
|
+
return node_or_leaf.label, node_or_leaf.label
|
|
821
|
+
else:
|
|
822
|
+
return None
|
|
823
|
+
|
|
824
|
+
elif isinstance(node_or_leaf, Node):
|
|
825
|
+
minimum = None # type: Optional[int]
|
|
826
|
+
maximum = None # type: Optional[int]
|
|
827
|
+
|
|
828
|
+
for child in node_or_leaf.children:
|
|
829
|
+
maybe_child_min_max = _determine_min_and_max_label(node_or_leaf=child)
|
|
830
|
+
if maybe_child_min_max is not None:
|
|
831
|
+
child_min, child_max = maybe_child_min_max
|
|
832
|
+
|
|
833
|
+
if minimum is not None:
|
|
834
|
+
minimum = min(minimum, child_min)
|
|
835
|
+
else:
|
|
836
|
+
minimum = child_min
|
|
837
|
+
|
|
838
|
+
if maximum is not None:
|
|
839
|
+
maximum = max(maximum, child_max)
|
|
840
|
+
else:
|
|
841
|
+
maximum = child_max
|
|
842
|
+
|
|
843
|
+
assert (minimum is not None and maximum is not None) or (
|
|
844
|
+
minimum is None and maximum is None
|
|
845
|
+
), (
|
|
846
|
+
f"Both minimum and maximum must be set or neither, "
|
|
847
|
+
f"but got: {minimum=}, {maximum=}"
|
|
848
|
+
)
|
|
849
|
+
|
|
850
|
+
if minimum is not None:
|
|
851
|
+
assert maximum is not None
|
|
852
|
+
return minimum, maximum
|
|
853
|
+
else:
|
|
854
|
+
assert maximum is None
|
|
855
|
+
return None
|
|
856
|
+
else:
|
|
857
|
+
assert_never(node_or_leaf)
|
|
858
|
+
|
|
859
|
+
|
|
860
|
+
@require(lambda indention: indention >= 0)
|
|
861
|
+
@require(lambda label_columns: label_columns >= 0)
|
|
862
|
+
def _write_recursively(
|
|
863
|
+
node_or_leaf: NodeOrLeaf, indention: int, label_columns: int, writer: TextIO
|
|
864
|
+
) -> None:
|
|
865
|
+
"""Write recursively the node or leaf as a human-readable text to the ``writer``."""
|
|
866
|
+
whitespace = " " * indention
|
|
867
|
+
|
|
868
|
+
if isinstance(node_or_leaf, Leaf):
|
|
869
|
+
if label_columns == 0:
|
|
870
|
+
label_prefix = ""
|
|
871
|
+
else:
|
|
872
|
+
if node_or_leaf.label is None:
|
|
873
|
+
label_prefix = " " * (label_columns + 2)
|
|
874
|
+
else:
|
|
875
|
+
# noinspection PyStringFormat
|
|
876
|
+
label_prefix = f"{{:0{label_columns}d}}: ".format(node_or_leaf.label)
|
|
877
|
+
|
|
878
|
+
instruction_str: str
|
|
879
|
+
|
|
880
|
+
if isinstance(node_or_leaf.instruction, InstructionChar):
|
|
881
|
+
instruction_str = f"char {node_or_leaf.instruction.character!r}"
|
|
882
|
+
|
|
883
|
+
elif isinstance(node_or_leaf.instruction, (InstructionSet, InstructionNotSet)):
|
|
884
|
+
ranges_str = "".join(
|
|
885
|
+
f"{rng.first}" if rng.first == rng.last else f"{rng.first}-{rng.last}"
|
|
886
|
+
for rng in node_or_leaf.instruction.ranges
|
|
887
|
+
)
|
|
888
|
+
|
|
889
|
+
if isinstance(node_or_leaf.instruction, InstructionSet):
|
|
890
|
+
instruction_str = f"set {ranges_str!r}"
|
|
891
|
+
elif isinstance(node_or_leaf.instruction, InstructionNotSet):
|
|
892
|
+
instruction_str = f"not-set {ranges_str!r}"
|
|
893
|
+
else:
|
|
894
|
+
assert_never(node_or_leaf.instruction)
|
|
895
|
+
|
|
896
|
+
elif isinstance(node_or_leaf.instruction, InstructionAny):
|
|
897
|
+
instruction_str = "any"
|
|
898
|
+
|
|
899
|
+
elif isinstance(node_or_leaf.instruction, InstructionMatch):
|
|
900
|
+
instruction_str = "match"
|
|
901
|
+
|
|
902
|
+
elif isinstance(node_or_leaf.instruction, InstructionJump):
|
|
903
|
+
instruction_str = f"jump {node_or_leaf.instruction.target}"
|
|
904
|
+
|
|
905
|
+
elif isinstance(node_or_leaf.instruction, InstructionSplit):
|
|
906
|
+
instruction_str = (
|
|
907
|
+
f"split {node_or_leaf.instruction.first_target}, "
|
|
908
|
+
f"{node_or_leaf.instruction.second_target}"
|
|
909
|
+
)
|
|
910
|
+
|
|
911
|
+
elif isinstance(node_or_leaf.instruction, InstructionEnd):
|
|
912
|
+
instruction_str = "end"
|
|
913
|
+
|
|
914
|
+
else:
|
|
915
|
+
assert_never(node_or_leaf.instruction)
|
|
916
|
+
|
|
917
|
+
writer.write(f"{label_prefix}{whitespace}{instruction_str}")
|
|
918
|
+
|
|
919
|
+
elif isinstance(node_or_leaf, Node):
|
|
920
|
+
if label_columns == 0:
|
|
921
|
+
label_prefix = ""
|
|
922
|
+
else:
|
|
923
|
+
label_prefix = " " * (label_columns + 2)
|
|
924
|
+
|
|
925
|
+
re_node_str = _render_re_node(node_or_leaf.re_node)
|
|
926
|
+
if len(node_or_leaf.children) == 0:
|
|
927
|
+
more_whitespace = " " * (indention + 1)
|
|
928
|
+
writer.write(
|
|
929
|
+
f"{label_prefix}{whitespace}# {re_node_str}\n"
|
|
930
|
+
f"{label_prefix}{whitespace}{{\n"
|
|
931
|
+
f"{label_prefix}{more_whitespace}# Nothing\n"
|
|
932
|
+
f"{label_prefix}{whitespace}}}"
|
|
933
|
+
)
|
|
934
|
+
elif len(node_or_leaf.children) == 1 and isinstance(
|
|
935
|
+
node_or_leaf.children[0], Leaf
|
|
936
|
+
):
|
|
937
|
+
if not isinstance(
|
|
938
|
+
node_or_leaf.children[0].instruction,
|
|
939
|
+
(InstructionSet, InstructionNotSet, InstructionAny, InstructionChar),
|
|
940
|
+
):
|
|
941
|
+
writer.write(f"{label_prefix}{whitespace}# {re_node_str}\n")
|
|
942
|
+
|
|
943
|
+
_write_recursively(
|
|
944
|
+
node_or_leaf=node_or_leaf.children[0],
|
|
945
|
+
indention=indention,
|
|
946
|
+
label_columns=label_columns,
|
|
947
|
+
writer=writer,
|
|
948
|
+
)
|
|
949
|
+
else:
|
|
950
|
+
writer.write(
|
|
951
|
+
f"{label_prefix}{whitespace}# {re_node_str}\n"
|
|
952
|
+
f"{label_prefix}{whitespace}{{\n"
|
|
953
|
+
)
|
|
954
|
+
for child in node_or_leaf.children:
|
|
955
|
+
_write_recursively(
|
|
956
|
+
node_or_leaf=child,
|
|
957
|
+
indention=indention + 1,
|
|
958
|
+
label_columns=label_columns,
|
|
959
|
+
writer=writer,
|
|
960
|
+
)
|
|
961
|
+
|
|
962
|
+
writer.write("\n")
|
|
963
|
+
|
|
964
|
+
writer.write(f"{label_prefix}{whitespace}}}")
|
|
965
|
+
|
|
966
|
+
else:
|
|
967
|
+
assert_never(node_or_leaf)
|
|
968
|
+
|
|
969
|
+
|
|
970
|
+
def dump(program: NodeOrLeaf) -> str:
|
|
971
|
+
"""Write out the program as a readable nested list of instructions."""
|
|
972
|
+
maybe_min_max_label = _determine_min_and_max_label(node_or_leaf=program)
|
|
973
|
+
|
|
974
|
+
if maybe_min_max_label is None:
|
|
975
|
+
label_columns = 0
|
|
976
|
+
else:
|
|
977
|
+
min_label, max_label = maybe_min_max_label
|
|
978
|
+
label_columns = max(len(str(min_label)), len(str(max_label)))
|
|
979
|
+
|
|
980
|
+
writer = io.StringIO()
|
|
981
|
+
_write_recursively(
|
|
982
|
+
node_or_leaf=program, indention=0, label_columns=label_columns, writer=writer
|
|
983
|
+
)
|
|
984
|
+
|
|
985
|
+
return writer.getvalue()
|