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.
Files changed (604) hide show
  1. aas_core_codegen/__init__.py +6 -0
  2. aas_core_codegen/__main__.py +8 -0
  3. aas_core_codegen/common.py +500 -0
  4. aas_core_codegen/cpp/__init__.py +1 -0
  5. aas_core_codegen/cpp/aas_common/__init__.py +6 -0
  6. aas_core_codegen/cpp/aas_common/_generate.py +713 -0
  7. aas_core_codegen/cpp/common.py +681 -0
  8. aas_core_codegen/cpp/constants/__init__.py +6 -0
  9. aas_core_codegen/cpp/constants/_generate.py +568 -0
  10. aas_core_codegen/cpp/description.py +654 -0
  11. aas_core_codegen/cpp/enhancing/__init__.py +4 -0
  12. aas_core_codegen/cpp/enhancing/_generate.py +993 -0
  13. aas_core_codegen/cpp/iteration/__init__.py +6 -0
  14. aas_core_codegen/cpp/iteration/_generate.py +2332 -0
  15. aas_core_codegen/cpp/jsonization/__init__.py +6 -0
  16. aas_core_codegen/cpp/jsonization/_generate.py +2619 -0
  17. aas_core_codegen/cpp/main.py +694 -0
  18. aas_core_codegen/cpp/naming.py +170 -0
  19. aas_core_codegen/cpp/optionaling.py +557 -0
  20. aas_core_codegen/cpp/pattern/__init__.py +6 -0
  21. aas_core_codegen/cpp/pattern/_generate.py +508 -0
  22. aas_core_codegen/cpp/revm/__init__.py +6 -0
  23. aas_core_codegen/cpp/revm/_generate.py +1149 -0
  24. aas_core_codegen/cpp/stringification/__init__.py +5 -0
  25. aas_core_codegen/cpp/stringification/_generate.py +955 -0
  26. aas_core_codegen/cpp/structure/__init__.py +7 -0
  27. aas_core_codegen/cpp/structure/_generate.py +1503 -0
  28. aas_core_codegen/cpp/transpilation.py +1383 -0
  29. aas_core_codegen/cpp/unrolling.py +159 -0
  30. aas_core_codegen/cpp/verification/__init__.py +6 -0
  31. aas_core_codegen/cpp/verification/_generate.py +3073 -0
  32. aas_core_codegen/cpp/visitation/__init__.py +6 -0
  33. aas_core_codegen/cpp/visitation/_generate.py +521 -0
  34. aas_core_codegen/cpp/wstringification/__init__.py +5 -0
  35. aas_core_codegen/cpp/wstringification/_generate.py +586 -0
  36. aas_core_codegen/cpp/xmlization/__init__.py +6 -0
  37. aas_core_codegen/cpp/xmlization/_generate.py +5373 -0
  38. aas_core_codegen/cpp/yielding.py +201 -0
  39. aas_core_codegen/csharp/__init__.py +1 -0
  40. aas_core_codegen/csharp/common.py +224 -0
  41. aas_core_codegen/csharp/constants/__init__.py +5 -0
  42. aas_core_codegen/csharp/constants/_generate.py +409 -0
  43. aas_core_codegen/csharp/copying/__init__.py +4 -0
  44. aas_core_codegen/csharp/copying/_generate.py +498 -0
  45. aas_core_codegen/csharp/description.py +1103 -0
  46. aas_core_codegen/csharp/enhancing/__init__.py +4 -0
  47. aas_core_codegen/csharp/enhancing/_generate.py +667 -0
  48. aas_core_codegen/csharp/jsonization/__init__.py +4 -0
  49. aas_core_codegen/csharp/jsonization/_generate.py +1630 -0
  50. aas_core_codegen/csharp/main.py +421 -0
  51. aas_core_codegen/csharp/naming.py +157 -0
  52. aas_core_codegen/csharp/reporting/__init__.py +4 -0
  53. aas_core_codegen/csharp/reporting/_generate.py +266 -0
  54. aas_core_codegen/csharp/stringification/__init__.py +4 -0
  55. aas_core_codegen/csharp/stringification/_generate.py +243 -0
  56. aas_core_codegen/csharp/structure/__init__.py +6 -0
  57. aas_core_codegen/csharp/structure/_generate.py +1341 -0
  58. aas_core_codegen/csharp/transpilation.py +990 -0
  59. aas_core_codegen/csharp/unrolling.py +211 -0
  60. aas_core_codegen/csharp/verification/__init__.py +6 -0
  61. aas_core_codegen/csharp/verification/_generate.py +1457 -0
  62. aas_core_codegen/csharp/visitation/__init__.py +5 -0
  63. aas_core_codegen/csharp/visitation/_generate.py +579 -0
  64. aas_core_codegen/csharp/xmlization/__init__.py +4 -0
  65. aas_core_codegen/csharp/xmlization/_generate.py +1980 -0
  66. aas_core_codegen/golang/__init__.py +1 -0
  67. aas_core_codegen/golang/aas_common/__init__.py +4 -0
  68. aas_core_codegen/golang/aas_common/_generate.py +152 -0
  69. aas_core_codegen/golang/common.py +303 -0
  70. aas_core_codegen/golang/constants/__init__.py +5 -0
  71. aas_core_codegen/golang/constants/_generate.py +339 -0
  72. aas_core_codegen/golang/description.py +501 -0
  73. aas_core_codegen/golang/enhancing/__init__.py +4 -0
  74. aas_core_codegen/golang/enhancing/_generate.py +527 -0
  75. aas_core_codegen/golang/jsonization/__init__.py +4 -0
  76. aas_core_codegen/golang/jsonization/_generate.py +1740 -0
  77. aas_core_codegen/golang/main.py +368 -0
  78. aas_core_codegen/golang/naming.py +412 -0
  79. aas_core_codegen/golang/pointering.py +631 -0
  80. aas_core_codegen/golang/reporting/__init__.py +4 -0
  81. aas_core_codegen/golang/reporting/_generate.py +218 -0
  82. aas_core_codegen/golang/stringification/__init__.py +4 -0
  83. aas_core_codegen/golang/stringification/_generate.py +394 -0
  84. aas_core_codegen/golang/structure/__init__.py +6 -0
  85. aas_core_codegen/golang/structure/_generate.py +1493 -0
  86. aas_core_codegen/golang/transpilation.py +1191 -0
  87. aas_core_codegen/golang/unrolling.py +159 -0
  88. aas_core_codegen/golang/verification/__init__.py +6 -0
  89. aas_core_codegen/golang/verification/_generate.py +1513 -0
  90. aas_core_codegen/golang/xmlization/__init__.py +4 -0
  91. aas_core_codegen/golang/xmlization/_generate.py +2507 -0
  92. aas_core_codegen/infer_for_schema/__init__.py +21 -0
  93. aas_core_codegen/infer_for_schema/_inline.py +693 -0
  94. aas_core_codegen/infer_for_schema/_len.py +527 -0
  95. aas_core_codegen/infer_for_schema/_pattern.py +311 -0
  96. aas_core_codegen/infer_for_schema/_set.py +394 -0
  97. aas_core_codegen/infer_for_schema/_stringify.py +201 -0
  98. aas_core_codegen/infer_for_schema/_types.py +135 -0
  99. aas_core_codegen/infer_for_schema/match.py +122 -0
  100. aas_core_codegen/intermediate/__init__.py +78 -0
  101. aas_core_codegen/intermediate/_hierarchy.py +397 -0
  102. aas_core_codegen/intermediate/_stringify.py +989 -0
  103. aas_core_codegen/intermediate/_translate.py +5128 -0
  104. aas_core_codegen/intermediate/_types.py +2901 -0
  105. aas_core_codegen/intermediate/construction.py +750 -0
  106. aas_core_codegen/intermediate/doc.py +344 -0
  107. aas_core_codegen/intermediate/pattern_verification.py +428 -0
  108. aas_core_codegen/intermediate/revm.py +985 -0
  109. aas_core_codegen/intermediate/type_inference.py +2266 -0
  110. aas_core_codegen/java/__init__.py +1 -0
  111. aas_core_codegen/java/common.py +197 -0
  112. aas_core_codegen/java/constants/__init__.py +5 -0
  113. aas_core_codegen/java/constants/_generate.py +334 -0
  114. aas_core_codegen/java/copying/__init__.py +4 -0
  115. aas_core_codegen/java/copying/_generate.py +502 -0
  116. aas_core_codegen/java/description.py +774 -0
  117. aas_core_codegen/java/enhancing/__init__.py +4 -0
  118. aas_core_codegen/java/enhancing/_generate.py +820 -0
  119. aas_core_codegen/java/generation/__init__.py +5 -0
  120. aas_core_codegen/java/generation/_generate.py +285 -0
  121. aas_core_codegen/java/jsonization/__init__.py +4 -0
  122. aas_core_codegen/java/jsonization/_generate.py +1472 -0
  123. aas_core_codegen/java/main.py +438 -0
  124. aas_core_codegen/java/naming.py +187 -0
  125. aas_core_codegen/java/optional.py +514 -0
  126. aas_core_codegen/java/reporting/__init__.py +4 -0
  127. aas_core_codegen/java/reporting/_generate.py +248 -0
  128. aas_core_codegen/java/stringification/__init__.py +4 -0
  129. aas_core_codegen/java/stringification/_generate.py +212 -0
  130. aas_core_codegen/java/structure/__init__.py +6 -0
  131. aas_core_codegen/java/structure/_generate.py +1767 -0
  132. aas_core_codegen/java/transpilation.py +1111 -0
  133. aas_core_codegen/java/verification/__init__.py +6 -0
  134. aas_core_codegen/java/verification/_generate.py +1536 -0
  135. aas_core_codegen/java/visitation/__init__.py +5 -0
  136. aas_core_codegen/java/visitation/_generate.py +689 -0
  137. aas_core_codegen/java/xmlization/__init__.py +4 -0
  138. aas_core_codegen/java/xmlization/_generate.py +2274 -0
  139. aas_core_codegen/jsonld/__init__.py +1 -0
  140. aas_core_codegen/jsonld/main.py +455 -0
  141. aas_core_codegen/jsonschema/__init__.py +1 -0
  142. aas_core_codegen/jsonschema/main.py +982 -0
  143. aas_core_codegen/main.py +245 -0
  144. aas_core_codegen/naming.py +133 -0
  145. aas_core_codegen/opcua/__init__.py +1 -0
  146. aas_core_codegen/opcua/main.py +1525 -0
  147. aas_core_codegen/opcua/naming.py +126 -0
  148. aas_core_codegen/parse/__init__.py +46 -0
  149. aas_core_codegen/parse/_rules.py +796 -0
  150. aas_core_codegen/parse/_stringify.py +532 -0
  151. aas_core_codegen/parse/_translate.py +3940 -0
  152. aas_core_codegen/parse/_types.py +973 -0
  153. aas_core_codegen/parse/retree/__init__.py +46 -0
  154. aas_core_codegen/parse/retree/_fix.py +434 -0
  155. aas_core_codegen/parse/retree/_parse.py +1143 -0
  156. aas_core_codegen/parse/retree/_render.py +298 -0
  157. aas_core_codegen/parse/retree/_stringify.py +199 -0
  158. aas_core_codegen/parse/retree/_types.py +362 -0
  159. aas_core_codegen/parse/retree/_visitor.py +70 -0
  160. aas_core_codegen/parse/tree.py +1303 -0
  161. aas_core_codegen/protobuf/__init__.py +1 -0
  162. aas_core_codegen/protobuf/common.py +225 -0
  163. aas_core_codegen/protobuf/description.py +1102 -0
  164. aas_core_codegen/protobuf/main.py +115 -0
  165. aas_core_codegen/protobuf/naming.py +143 -0
  166. aas_core_codegen/protobuf/structure/__init__.py +6 -0
  167. aas_core_codegen/protobuf/structure/_generate.py +502 -0
  168. aas_core_codegen/py.typed +1 -0
  169. aas_core_codegen/python/__init__.py +1 -0
  170. aas_core_codegen/python/aas_common/__init__.py +4 -0
  171. aas_core_codegen/python/aas_common/_generate.py +63 -0
  172. aas_core_codegen/python/common.py +406 -0
  173. aas_core_codegen/python/constants/__init__.py +5 -0
  174. aas_core_codegen/python/constants/_generate.py +377 -0
  175. aas_core_codegen/python/description.py +508 -0
  176. aas_core_codegen/python/jsonization/__init__.py +4 -0
  177. aas_core_codegen/python/jsonization/_generate.py +1391 -0
  178. aas_core_codegen/python/main.py +323 -0
  179. aas_core_codegen/python/naming.py +255 -0
  180. aas_core_codegen/python/stringification/__init__.py +4 -0
  181. aas_core_codegen/python/stringification/_generate.py +129 -0
  182. aas_core_codegen/python/structure/__init__.py +6 -0
  183. aas_core_codegen/python/structure/_generate.py +1801 -0
  184. aas_core_codegen/python/transpilation.py +958 -0
  185. aas_core_codegen/python/unrolling.py +156 -0
  186. aas_core_codegen/python/verification/__init__.py +6 -0
  187. aas_core_codegen/python/verification/_generate.py +1471 -0
  188. aas_core_codegen/python/xmlization/__init__.py +4 -0
  189. aas_core_codegen/python/xmlization/_generate.py +3003 -0
  190. aas_core_codegen/python_protobuf/__init__.py +1 -0
  191. aas_core_codegen/python_protobuf/main.py +1424 -0
  192. aas_core_codegen/python_protobuf/naming.py +85 -0
  193. aas_core_codegen/rdf_shacl/__init__.py +1 -0
  194. aas_core_codegen/rdf_shacl/_description.py +351 -0
  195. aas_core_codegen/rdf_shacl/common.py +206 -0
  196. aas_core_codegen/rdf_shacl/main.py +114 -0
  197. aas_core_codegen/rdf_shacl/naming.py +145 -0
  198. aas_core_codegen/rdf_shacl/rdf.py +435 -0
  199. aas_core_codegen/rdf_shacl/shacl.py +453 -0
  200. aas_core_codegen/run.py +124 -0
  201. aas_core_codegen/smoke/__init__.py +1 -0
  202. aas_core_codegen/smoke/main.py +219 -0
  203. aas_core_codegen/specific_implementations.py +72 -0
  204. aas_core_codegen/stringify.py +333 -0
  205. aas_core_codegen/typescript/__init__.py +1 -0
  206. aas_core_codegen/typescript/aas_common/__init__.py +4 -0
  207. aas_core_codegen/typescript/aas_common/_generate.py +472 -0
  208. aas_core_codegen/typescript/common.py +340 -0
  209. aas_core_codegen/typescript/constants/__init__.py +5 -0
  210. aas_core_codegen/typescript/constants/_generate.py +347 -0
  211. aas_core_codegen/typescript/description.py +530 -0
  212. aas_core_codegen/typescript/jsonization/__init__.py +4 -0
  213. aas_core_codegen/typescript/jsonization/_generate.py +1510 -0
  214. aas_core_codegen/typescript/main.py +258 -0
  215. aas_core_codegen/typescript/naming.py +189 -0
  216. aas_core_codegen/typescript/stringification/__init__.py +4 -0
  217. aas_core_codegen/typescript/stringification/_generate.py +367 -0
  218. aas_core_codegen/typescript/structure/__init__.py +6 -0
  219. aas_core_codegen/typescript/structure/_generate.py +2500 -0
  220. aas_core_codegen/typescript/transpilation.py +1051 -0
  221. aas_core_codegen/typescript/unrolling.py +159 -0
  222. aas_core_codegen/typescript/verification/__init__.py +6 -0
  223. aas_core_codegen/typescript/verification/_generate.py +1578 -0
  224. aas_core_codegen/xsd/__init__.py +1 -0
  225. aas_core_codegen/xsd/main.py +1187 -0
  226. aas_core_codegen/xsd/naming.py +83 -0
  227. aas_core_codegen/yielding/__init__.py +1 -0
  228. aas_core_codegen/yielding/flow.py +139 -0
  229. aas_core_codegen/yielding/linear.py +754 -0
  230. aas_core_codegen-0.0.16.dist-info/METADATA +211 -0
  231. aas_core_codegen-0.0.16.dist-info/RECORD +604 -0
  232. aas_core_codegen-0.0.16.dist-info/WHEEL +5 -0
  233. aas_core_codegen-0.0.16.dist-info/entry_points.txt +3 -0
  234. aas_core_codegen-0.0.16.dist-info/licenses/AUTHORS +9 -0
  235. aas_core_codegen-0.0.16.dist-info/licenses/LICENSE +23 -0
  236. aas_core_codegen-0.0.16.dist-info/top_level.txt +2 -0
  237. dev/continuous_integration/__init__.py +1 -0
  238. dev/continuous_integration/check_help_in_readme.py +208 -0
  239. dev/continuous_integration/check_init_and_pyproject_consistent.py +154 -0
  240. dev/continuous_integration/precommit.py +400 -0
  241. dev/dev_scripts/__init__.py +1 -0
  242. dev/dev_scripts/compare_rendered_regexes_against_source_py.py +42 -0
  243. dev/dev_scripts/copy_to_aas_core3_cpp.py +100 -0
  244. dev/dev_scripts/copy_to_aas_core3_java.py +90 -0
  245. dev/dev_scripts/download_latest_aas_core_meta_v3.py +114 -0
  246. dev/dev_scripts/draw_bipartite_graph_based_on_lines.py +37 -0
  247. dev/dev_scripts/run_tests_with_rerecord.py +69 -0
  248. dev/dev_scripts/update_to_aas_core_meta.py +174 -0
  249. dev/integration_tests/input/jsonschema/boilerplate/main.py +55 -0
  250. dev/integration_tests/input/meta_model.py +38 -0
  251. dev/integration_tests/input/python/boilerplate/main.py +153 -0
  252. dev/integration_tests/main.py +258 -0
  253. dev/test_data/csharp/test_structure/concrete_class_with_descendants/meta_model.py +15 -0
  254. dev/test_data/csharp/test_structure/constructor_without_arguments/all_properties_optional/meta_model.py +9 -0
  255. dev/test_data/csharp/test_structure/constructor_without_arguments/no_properties/meta_model.py +6 -0
  256. dev/test_data/csharp/test_verification/builtin_functions/len/on_list/meta_model.py +20 -0
  257. dev/test_data/csharp/test_verification/builtin_functions/len/on_str/meta_model.py +16 -0
  258. dev/test_data/csharp/test_verification/pattern_verification/utf32_as_literal/as_prefix/meta_model.py +8 -0
  259. dev/test_data/csharp/test_verification/pattern_verification/utf32_as_literal/as_suffix/meta_model.py +8 -0
  260. dev/test_data/csharp/test_verification/pattern_verification/utf32_as_literal/in_group_with_quantifier/meta_model.py +8 -0
  261. dev/test_data/csharp/test_verification/pattern_verification/utf32_as_literal/in_the_middle/meta_model.py +8 -0
  262. dev/test_data/csharp/test_verification/pattern_verification/utf32_as_literal/in_union/meta_model.py +8 -0
  263. dev/test_data/csharp/test_verification/pattern_verification/utf32_as_literal/single_utf32_literal/meta_model.py +8 -0
  264. dev/test_data/csharp/test_verification/pattern_verification/utf32_as_literal/with_quantifier_within_group/meta_model.py +8 -0
  265. dev/test_data/csharp/test_verification/pattern_verification/utf32_as_literal/with_quantifier_without_group/meta_model.py +8 -0
  266. dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/literal/at_the_beginning/meta_model.py +8 -0
  267. dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/literal/at_the_end/meta_model.py +8 -0
  268. dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/literal/in_the_middle/meta_model.py +8 -0
  269. dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/literal/multiple/meta_model.py +8 -0
  270. dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/literal/single/meta_model.py +8 -0
  271. dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/literal/single_with_quantifier/meta_model.py +8 -0
  272. dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/range/mixed_with_non_utf32/meta_model.py +8 -0
  273. dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/range/more_than_two_high_surrogates/meta_model.py +8 -0
  274. dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/range/multiple_utf32_ranges/meta_model.py +8 -0
  275. 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
  276. dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/range/same_high_surrogate/meta_model.py +8 -0
  277. dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/range/same_high_surrogate_with_quantifier/meta_model.py +8 -0
  278. dev/test_data/csharp/test_verification/pattern_verification/utf32_in_character_set/range/two_high_surrogates/meta_model.py +8 -0
  279. dev/test_data/intermediate/expected/class/empty/meta_model.py +6 -0
  280. dev/test_data/intermediate/expected/class/implementation_specific_method/meta_model.py +8 -0
  281. dev/test_data/intermediate/expected/class/inheritance/meta_model.py +41 -0
  282. dev/test_data/intermediate/expected/class/methods_with_contracts/meta_model.py +15 -0
  283. dev/test_data/intermediate/expected/class/only_method_no_property/meta_model.py +7 -0
  284. dev/test_data/intermediate/expected/class/only_property_no_method/meta_model.py +9 -0
  285. dev/test_data/intermediate/expected/constant/constant_set/of_enum/meta_model.py +12 -0
  286. dev/test_data/intermediate/expected/constant/constant_set/of_str/meta_model.py +4 -0
  287. dev/test_data/intermediate/expected/constant/constant_set/with_description/meta_model.py +6 -0
  288. dev/test_data/intermediate/expected/constant/constant_set/with_superset_of/meta_model.py +14 -0
  289. dev/test_data/intermediate/expected/constant/constant_str/only_value/meta_model.py +7 -0
  290. dev/test_data/intermediate/expected/constant/constant_str/with_description/meta_model.py +5 -0
  291. dev/test_data/intermediate/expected/documentation/docstring_with_special_characters_in_literal/meta_model.py +20 -0
  292. dev/test_data/intermediate/expected/documentation/docstring_with_special_characters_outside_literal/meta_model.py +20 -0
  293. dev/test_data/intermediate/expected/empty/meta_model.py +2 -0
  294. dev/test_data/intermediate/expected/enumeration/meta_model.py +9 -0
  295. dev/test_data/intermediate/expected/interface/basic/meta_model.py +14 -0
  296. dev/test_data/intermediate/expected/interface/empty/meta_model.py +7 -0
  297. dev/test_data/intermediate/expected/interface/inheritance/meta_model.py +27 -0
  298. dev/test_data/intermediate/expected/interface/method_signature/meta_model.py +10 -0
  299. dev/test_data/intermediate/expected/interface/only_constructor/meta_model.py +11 -0
  300. dev/test_data/intermediate/expected/method/non_mutating/implementation_specific/meta_model.py +12 -0
  301. dev/test_data/intermediate/expected/method/non_mutating/understood/meta_model.py +11 -0
  302. dev/test_data/intermediate/expected/type_annotation/atomic/meta_model.py +9 -0
  303. dev/test_data/intermediate/expected/type_annotation/subscripted/class/meta_model.py +13 -0
  304. dev/test_data/intermediate/expected/type_annotation/subscripted/primitive/meta_model.py +9 -0
  305. dev/test_data/intermediate/unexpected/constant_set/of_enum/enumeration_literals_in_subset_outside_of_superset/meta_model.py +20 -0
  306. dev/test_data/intermediate/unexpected/constant_set/of_enum/invalid_literal/meta_model.py +11 -0
  307. dev/test_data/intermediate/unexpected/constant_set/of_enum/mismatch_between_enumeration_and_literal/meta_model.py +30 -0
  308. dev/test_data/intermediate/unexpected/constant_set/of_enum/mismatch_in_enumerations_between_subset_and_superset/meta_model.py +21 -0
  309. dev/test_data/intermediate/unexpected/constant_set/of_str/literals_in_subset_outside_of_superset/meta_model.py +18 -0
  310. dev/test_data/intermediate/unexpected/constant_set/of_str/mismatch_between_type_annotation_and_literals/meta_model.py +10 -0
  311. dev/test_data/intermediate/unexpected/constant_set/of_str/superset_and_subset_mismatch_in_type/meta_model.py +12 -0
  312. dev/test_data/intermediate/unexpected/constraints/dangling_constraintref/meta_model.py +18 -0
  313. dev/test_data/intermediate/unexpected/constraints/duplicate_constraints/meta_model.py +20 -0
  314. dev/test_data/intermediate/unexpected/documentation/unexpected_documentation_elements/meta_model.py +34 -0
  315. dev/test_data/intermediate/unexpected/invariant/class_invariant_uses_re/meta_model.py +10 -0
  316. dev/test_data/intermediate/unexpected/invariant/invariant_of_constrained_primitive_uses_re/meta_model.py +7 -0
  317. dev/test_data/intermediate/unexpected/invariant/unexpected_argument_count_to_len/meta_model.py +20 -0
  318. dev/test_data/intermediate/unexpected/invariant/unhandled_built_in_function/meta_model.py +16 -0
  319. dev/test_data/intermediate/unexpected/method_definitions/non_constant_default/meta_model.py +7 -0
  320. dev/test_data/intermediate/unexpected/optional_constructor_arguments_wo_default/default_non_none/meta_model.py +16 -0
  321. dev/test_data/intermediate/unexpected/optional_constructor_arguments_wo_default/no_default/meta_model.py +16 -0
  322. dev/test_data/intermediate/unexpected/properties_and_constructor_arguments_do_not_match/after_inheritance/meta_model.py +58 -0
  323. dev/test_data/intermediate/unexpected/properties_and_constructor_arguments_do_not_match/type_missmatch/meta_model.py +9 -0
  324. dev/test_data/intermediate/unexpected/properties_and_constructor_arguments_do_not_match/within_class/meta_model.py +22 -0
  325. dev/test_data/jsonschema/test_main/regression_when_len_constraints_on_inherited_property/meta_model.py +28 -0
  326. dev/test_data/opcua/test_main/abstract_and_concrete_classes/meta_model.py +37 -0
  327. dev/test_data/opcua/test_main/classes_with_invariants/meta_model.py +21 -0
  328. dev/test_data/opcua/test_main/concrete_class_with_descendant/meta_model.py +27 -0
  329. dev/test_data/opcua/test_main/concrete_class_with_enum/meta_model.py +21 -0
  330. dev/test_data/opcua/test_main/concrete_class_with_list_of_instances/meta_model.py +21 -0
  331. dev/test_data/opcua/test_main/concrete_class_with_primitive_attributes/meta_model.py +41 -0
  332. dev/test_data/opcua/test_main/concrete_class_with_string/meta_model.py +13 -0
  333. dev/test_data/opcua/test_main/constrained_primitive/meta_model.py +20 -0
  334. dev/test_data/opcua/test_main/multiple_inheritance/meta_model.py +25 -0
  335. dev/test_data/parse/expected/constant/constant_set/of_enum/meta_model.py +12 -0
  336. dev/test_data/parse/expected/constant/constant_set/of_str/meta_model.py +4 -0
  337. dev/test_data/parse/expected/constant/constant_set/with_description/meta_model.py +6 -0
  338. dev/test_data/parse/expected/constant/constant_set/with_superset_of/meta_model.py +14 -0
  339. dev/test_data/parse/expected/constant/constant_str/only_value/meta_model.py +7 -0
  340. dev/test_data/parse/expected/constant/constant_str/with_description/meta_model.py +5 -0
  341. dev/test_data/parse/expected/enum/ok/meta_model.py +15 -0
  342. dev/test_data/parse/expected/implementation_specific_class/properties_and_methods_in_implementation_specific_class/meta_model.py +17 -0
  343. dev/test_data/parse/expected/inheritance/basic/meta_model.py +11 -0
  344. dev/test_data/parse/expected/inheritance/diamond/meta_model.py +26 -0
  345. dev/test_data/parse/expected/inheritance/inheritance_from_concrete_class/meta_model.py +10 -0
  346. dev/test_data/parse/expected/invariants/in_relation/meta_model.py +16 -0
  347. dev/test_data/parse/expected/method/arguments/meta_model.py +7 -0
  348. dev/test_data/parse/expected/method/basic/meta_model.py +7 -0
  349. dev/test_data/parse/expected/method/contracts/condition_as_keyword_argument/meta_model.py +8 -0
  350. dev/test_data/parse/expected/method/contracts/condition_as_positional_argument/meta_model.py +8 -0
  351. dev/test_data/parse/expected/method/contracts/description_as_keyword_argument/meta_model.py +8 -0
  352. dev/test_data/parse/expected/method/contracts/description_as_positional_argument/meta_model.py +8 -0
  353. dev/test_data/parse/expected/method/contracts/multiple_contracts_in_order/meta_model.py +17 -0
  354. dev/test_data/parse/expected/method/contracts/postcondition/basic/meta_model.py +10 -0
  355. dev/test_data/parse/expected/method/contracts/postcondition/snapshot/with_keyword_arguments/meta_model.py +9 -0
  356. dev/test_data/parse/expected/method/contracts/postcondition/snapshot/with_positional_arguments/meta_model.py +9 -0
  357. dev/test_data/parse/expected/method/default/meta_model.py +9 -0
  358. dev/test_data/parse/expected/method/description/meta_model.py +8 -0
  359. dev/test_data/parse/expected/method/is_implementation_specific/meta_model.py +8 -0
  360. dev/test_data/parse/expected/method/non_mutating/meta_model.py +11 -0
  361. dev/test_data/parse/expected/method/returns_none/meta_model.py +7 -0
  362. dev/test_data/parse/expected/method/returns_something/meta_model.py +7 -0
  363. dev/test_data/parse/expected/single_class/description/meta_model.py +12 -0
  364. dev/test_data/parse/expected/single_class/empty/meta_model.py +6 -0
  365. dev/test_data/parse/expected/single_class/property/description/meta_model.py +14 -0
  366. dev/test_data/parse/expected/single_class/property/mandatory/meta_model.py +6 -0
  367. dev/test_data/parse/expected/single_class/property/optional/meta_model.py +6 -0
  368. dev/test_data/parse/expected/single_class/property/recursion_to_entity/meta_model.py +6 -0
  369. dev/test_data/parse/unexpected/class_decorators/non_name_decorator/meta_model.py +7 -0
  370. dev/test_data/parse/unexpected/class_decorators/unknown_decorator/meta_model.py +7 -0
  371. dev/test_data/parse/unexpected/class_definitions/is_abstract_and_implementation_specific/meta_model.py +8 -0
  372. dev/test_data/parse/unexpected/class_definitions/unexpected_docstring_before_a_method/meta_model.py +11 -0
  373. dev/test_data/parse/unexpected/class_definitions/unexpected_docstring_for_a_pass/meta_model.py +9 -0
  374. dev/test_data/parse/unexpected/class_definitions/unexpected_double_description_for_a_property/meta_model.py +10 -0
  375. dev/test_data/parse/unexpected/class_inheritances/inheriting_from_implementation_specific_parent/meta_model.py +20 -0
  376. dev/test_data/parse/unexpected/class_inheritances/non_name_super_class/meta_model.py +6 -0
  377. dev/test_data/parse/unexpected/enum/expression_as_assignment_value/meta_model.py +6 -0
  378. dev/test_data/parse/unexpected/enum/non_assignment/meta_model.py +8 -0
  379. dev/test_data/parse/unexpected/enum/non_string_literal/meta_model.py +6 -0
  380. dev/test_data/parse/unexpected/enum/unexpected_inheritance/meta_model.py +6 -0
  381. dev/test_data/parse/unexpected/method_contracts/contract/non_lambda_condition/meta_model.py +8 -0
  382. dev/test_data/parse/unexpected/method_contracts/contract/non_string_literal_description/meta_model.py +8 -0
  383. dev/test_data/parse/unexpected/method_contracts/contract/without_any_arguments/meta_model.py +8 -0
  384. dev/test_data/parse/unexpected/method_contracts/contract/without_condition/meta_model.py +8 -0
  385. dev/test_data/parse/unexpected/method_contracts/postcondition/OLD_in_postcondition_without_snapshot/meta_model.py +8 -0
  386. dev/test_data/parse/unexpected/method_contracts/postcondition/argument_missing_in_function/meta_model.py +8 -0
  387. dev/test_data/parse/unexpected/method_contracts/precondition/argument_missing_in_function/meta_model.py +8 -0
  388. dev/test_data/parse/unexpected/method_contracts/snapshot/argument_missing_in_function/meta_model.py +8 -0
  389. dev/test_data/parse/unexpected/method_contracts/snapshot/capture_not_a_lambda/meta_model.py +8 -0
  390. dev/test_data/parse/unexpected/method_contracts/snapshot/invalid_name/meta_model.py +8 -0
  391. dev/test_data/parse/unexpected/method_contracts/snapshot/name_not_a_string_literal/meta_model.py +8 -0
  392. dev/test_data/parse/unexpected/method_contracts/snapshot/without_a_capture/meta_model.py +8 -0
  393. dev/test_data/parse/unexpected/method_contracts/snapshot/without_a_name/meta_model.py +8 -0
  394. dev/test_data/parse/unexpected/method_decorators/non_mutating/non_mutating_constructor/meta_model.py +8 -0
  395. dev/test_data/parse/unexpected/method_decorators/non_mutating/non_mutating_verification_function/meta_model.py +8 -0
  396. dev/test_data/parse/unexpected/method_decorators/non_name_decorator/meta_model.py +8 -0
  397. dev/test_data/parse/unexpected/method_decorators/unknown_call_decorator/meta_model.py +8 -0
  398. dev/test_data/parse/unexpected/method_decorators/unknown_name_decorator/meta_model.py +8 -0
  399. dev/test_data/parse/unexpected/method_definitions/argument_with_final/meta_model.py +7 -0
  400. dev/test_data/parse/unexpected/method_definitions/argument_without_a_type_annotation/meta_model.py +7 -0
  401. dev/test_data/parse/unexpected/method_definitions/default_for_self/meta_model.py +7 -0
  402. dev/test_data/parse/unexpected/method_definitions/dunder/meta_model.py +7 -0
  403. dev/test_data/parse/unexpected/method_definitions/init_with_return_type/meta_model.py +7 -0
  404. dev/test_data/parse/unexpected/method_definitions/with_keyword_only_arguments/meta_model.py +7 -0
  405. dev/test_data/parse/unexpected/method_definitions/with_positional_arguments/meta_model.py +7 -0
  406. dev/test_data/parse/unexpected/method_definitions/with_type_annotation_for_self/meta_model.py +7 -0
  407. dev/test_data/parse/unexpected/method_definitions/with_variable_arguments/meta_model.py +7 -0
  408. dev/test_data/parse/unexpected/method_definitions/with_variable_keyword_arguments/meta_model.py +7 -0
  409. dev/test_data/parse/unexpected/method_definitions/without_arguments/meta_model.py +7 -0
  410. dev/test_data/parse/unexpected/method_definitions/without_self/meta_model.py +7 -0
  411. dev/test_data/parse/unexpected/method_definitions/without_type_annotation_for_result/meta_model.py +7 -0
  412. dev/test_data/parse/unexpected/property_definitions/final_without_subscript/meta_model.py +6 -0
  413. dev/test_data/parse/unexpected/property_definitions/nested_final/meta_model.py +6 -0
  414. dev/test_data/parse/unexpected/property_definitions/non_simple/meta_model.py +6 -0
  415. dev/test_data/parse/unexpected/property_definitions/unexpected_assignment/meta_model.py +6 -0
  416. dev/test_data/parse/unexpected/property_definitions/unexpected_non_name_property/meta_model.py +6 -0
  417. dev/test_data/parse/unexpected/property_definitions/without_type_annotation/meta_model.py +6 -0
  418. dev/test_data/parse/unexpected/symbol_table/constant_set_with_a_non_set_subset/meta_model.py +6 -0
  419. dev/test_data/parse/unexpected/symbol_table/dangling_inheritance/meta_model.py +6 -0
  420. dev/test_data/parse/unexpected/symbol_table/dangling_reference_in_type_annotation_of_a_property/meta_model.py +6 -0
  421. dev/test_data/parse/unexpected/symbol_table/dangling_reference_in_type_annotation_of_an_argument/meta_model.py +7 -0
  422. dev/test_data/parse/unexpected/symbol_table/dangling_reference_in_type_annotation_of_constant_set/meta_model.py +6 -0
  423. dev/test_data/parse/unexpected/symbol_table/dangling_subset_in_constant_set/meta_model.py +4 -0
  424. dev/test_data/parse/unexpected/symbol_table/inheritance_from_non_class/meta_model.py +10 -0
  425. dev/test_data/parse_retree/expected/character_set/common_escaping/source.py +1 -0
  426. dev/test_data/parse_retree/expected/character_set/complementing/double_caret/source.py +1 -0
  427. dev/test_data/parse_retree/expected/character_set/complementing/multiple_ranges/source.py +1 -0
  428. dev/test_data/parse_retree/expected/character_set/complementing/suffix_dash/source.py +1 -0
  429. dev/test_data/parse_retree/expected/character_set/escape_first_caret/source.py +1 -0
  430. dev/test_data/parse_retree/expected/character_set/literals_which_need_no_escaping_in_characters_set_but_need_escaping_outside/source.py +1 -0
  431. dev/test_data/parse_retree/expected/character_set/multiple_ranges/source.py +1 -0
  432. dev/test_data/parse_retree/expected/character_set/single_literal/source.py +1 -0
  433. dev/test_data/parse_retree/expected/character_set/single_range/source.py +1 -0
  434. dev/test_data/parse_retree/expected/character_set/unescaped_dash/only_dash/source.py +1 -0
  435. dev/test_data/parse_retree/expected/character_set/unescaped_dash/prefix_dash/source.py +1 -0
  436. dev/test_data/parse_retree/expected/character_set/unescaped_dash/suffix_dash/source.py +1 -0
  437. dev/test_data/parse_retree/expected/dot/source.py +1 -0
  438. dev/test_data/parse_retree/expected/empty/group/source.py +1 -0
  439. dev/test_data/parse_retree/expected/empty/group_in_a_group/source.py +1 -0
  440. dev/test_data/parse_retree/expected/empty/group_of_union_of_empty_concatenations/source.py +1 -0
  441. dev/test_data/parse_retree/expected/empty/regex/source.py +1 -0
  442. dev/test_data/parse_retree/expected/empty/union_of_empty_concatenations/source.py +1 -0
  443. dev/test_data/parse_retree/expected/escaped_literals/source.py +1 -0
  444. dev/test_data/parse_retree/expected/formatted_value/at_the_beginning/source.py +1 -0
  445. dev/test_data/parse_retree/expected/formatted_value/at_the_end/source.py +1 -0
  446. dev/test_data/parse_retree/expected/formatted_value/in_the_middle/source.py +1 -0
  447. dev/test_data/parse_retree/expected/formatted_value/single_formatted_value/source.py +1 -0
  448. dev/test_data/parse_retree/expected/literal/source.py +1 -0
  449. dev/test_data/parse_retree/expected/quantifier/greedy/at_least_3/source.py +1 -0
  450. dev/test_data/parse_retree/expected/quantifier/greedy/at_least_one/source.py +1 -0
  451. dev/test_data/parse_retree/expected/quantifier/greedy/at_most_3/source.py +1 -0
  452. dev/test_data/parse_retree/expected/quantifier/greedy/exactly_3/source.py +1 -0
  453. dev/test_data/parse_retree/expected/quantifier/greedy/maybe/source.py +1 -0
  454. dev/test_data/parse_retree/expected/quantifier/greedy/zero_or_more/source.py +1 -0
  455. dev/test_data/parse_retree/expected/quantifier/non_greedy/at_least_3/source.py +1 -0
  456. dev/test_data/parse_retree/expected/quantifier/non_greedy/at_least_one/source.py +1 -0
  457. dev/test_data/parse_retree/expected/quantifier/non_greedy/at_most_3/source.py +1 -0
  458. dev/test_data/parse_retree/expected/quantifier/non_greedy/exactly_3/source.py +1 -0
  459. dev/test_data/parse_retree/expected/quantifier/non_greedy/maybe/source.py +1 -0
  460. dev/test_data/parse_retree/expected/quantifier/non_greedy/zero_or_more/source.py +1 -0
  461. dev/test_data/parse_retree/expected/quantifier/on_a_character_set/source.py +1 -0
  462. dev/test_data/parse_retree/expected/quantifier/on_a_formatted_value/source.py +1 -0
  463. dev/test_data/parse_retree/expected/quantifier/on_a_group/source.py +1 -0
  464. dev/test_data/parse_retree/expected/quantifier/on_a_literal/source.py +1 -0
  465. dev/test_data/parse_retree/expected/start_and_stop_symbols/double_end_symbol/source.py +1 -0
  466. dev/test_data/parse_retree/expected/start_and_stop_symbols/double_start_symbol/source.py +1 -0
  467. dev/test_data/parse_retree/expected/start_and_stop_symbols/end_symbol_in_the_middle/source.py +1 -0
  468. dev/test_data/parse_retree/expected/start_and_stop_symbols/only_start_symbol/source.py +1 -0
  469. dev/test_data/parse_retree/expected/start_and_stop_symbols/only_stop_symbol/source.py +1 -0
  470. dev/test_data/parse_retree/expected/start_and_stop_symbols/start_symbol_at_the_beginning/source.py +1 -0
  471. dev/test_data/parse_retree/expected/start_and_stop_symbols/start_symbol_in_the_middle/source.py +1 -0
  472. dev/test_data/parse_retree/expected/start_and_stop_symbols/stop_symbol_at_the_end/source.py +1 -0
  473. dev/test_data/parse_retree/expected/union/of_character_sets/source.py +1 -0
  474. dev/test_data/parse_retree/expected/union/of_groups/source.py +1 -0
  475. dev/test_data/parse_retree/expected/union/of_string_literals/source.py +1 -0
  476. dev/test_data/parse_retree/expected/union/within_group/source.py +1 -0
  477. dev/test_data/parse_retree/expected/whitespace/source.py +1 -0
  478. dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/Uxxxxxxxx_out_of_range/source.py +1 -0
  479. dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/only_backslash/source.py +1 -0
  480. dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/short_Uxxxxxxxx/source.py +1 -0
  481. dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/short_uxxxx/source.py +1 -0
  482. dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/short_x/source.py +1 -0
  483. dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/unexpected_escaping/source.py +1 -0
  484. dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/unhandled/digit/source.py +1 -0
  485. dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/unhandled/not_digit/source.py +1 -0
  486. dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/unhandled/not_whitespace/source.py +1 -0
  487. dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/unhandled/not_word/source.py +1 -0
  488. dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/unhandled/whitespace/source.py +1 -0
  489. dev/test_data/parse_retree/unexpected/improper_escaping/character_literal/unhandled/word/source.py +1 -0
  490. dev/test_data/parse_retree/unexpected/improper_escaping/range_character/Uxxxxxxxx_out_of_range/source.py +1 -0
  491. dev/test_data/parse_retree/unexpected/improper_escaping/range_character/only_backslash/source.py +1 -0
  492. dev/test_data/parse_retree/unexpected/improper_escaping/range_character/short_Uxxxxxxxx/source.py +1 -0
  493. dev/test_data/parse_retree/unexpected/improper_escaping/range_character/short_uxxxx/source.py +1 -0
  494. dev/test_data/parse_retree/unexpected/improper_escaping/range_character/short_x/source.py +1 -0
  495. dev/test_data/parse_retree/unexpected/improper_escaping/range_character/unexpected_escaping/source.py +1 -0
  496. dev/test_data/parse_retree/unexpected/improper_escaping/range_character/unhandled/digit/source.py +1 -0
  497. dev/test_data/parse_retree/unexpected/improper_escaping/range_character/unhandled/not_digit/source.py +1 -0
  498. dev/test_data/parse_retree/unexpected/improper_escaping/range_character/unhandled/not_whitespace/source.py +1 -0
  499. dev/test_data/parse_retree/unexpected/improper_escaping/range_character/unhandled/not_word/source.py +1 -0
  500. dev/test_data/parse_retree/unexpected/improper_escaping/range_character/unhandled/whitespace/source.py +1 -0
  501. dev/test_data/parse_retree/unexpected/improper_escaping/range_character/unhandled/word/source.py +1 -0
  502. dev/test_data/parse_retree/unexpected/invalid_character_range/source.py +1 -0
  503. dev/test_data/parse_retree/unexpected/invalid_quantifier/at_least_x/source.py +1 -0
  504. dev/test_data/parse_retree/unexpected/invalid_quantifier/between_3_and_x/source.py +1 -0
  505. dev/test_data/parse_retree/unexpected/invalid_quantifier/exactly_x/source.py +1 -0
  506. dev/test_data/parse_retree/unexpected/unhandled_group_directives/source.py +1 -0
  507. dev/test_data/parse_retree/unexpected/unterminated/character_set/source.py +1 -0
  508. dev/test_data/parse_retree/unexpected/unterminated/group/source.py +1 -0
  509. dev/test_data/parse_retree/unexpected/unterminated/group_of_union_of_empty_concatenations/source.py +1 -0
  510. dev/test_data/parse_retree/unexpected/unterminated/quantifier/source.py +1 -0
  511. dev/test_data/parse_retree/unexpected/unterminated/quantifier_with_comma/source.py +1 -0
  512. dev/test_data/parse_retree/unexpected/unterminated/quantifier_with_number_and_comma/source.py +1 -0
  513. dev/test_data/proto/test_main/expected/abstract_and_concrete_classes/meta_model.py +37 -0
  514. dev/test_data/proto/test_main/expected/concrete_class_with_descendants/meta_model.py +30 -0
  515. dev/test_data/proto/test_main/expected/concrete_class_with_enum/meta_model.py +21 -0
  516. dev/test_data/proto/test_main/expected/concrete_class_with_list_of_instances/meta_model.py +21 -0
  517. dev/test_data/proto/test_main/expected/concrete_class_with_primitive_attributes/meta_model.py +41 -0
  518. dev/test_data/python_protobuf/test_main/abstract_and_concrete_classes/expected_output/pbization.py +532 -0
  519. dev/test_data/python_protobuf/test_main/abstract_and_concrete_classes/meta_model.py +37 -0
  520. dev/test_data/python_protobuf/test_main/concrete_class_with_descendant/expected_output/pbization.py +527 -0
  521. dev/test_data/python_protobuf/test_main/concrete_class_with_descendant/meta_model.py +27 -0
  522. dev/test_data/python_protobuf/test_main/concrete_class_with_enum/expected_output/pbization.py +290 -0
  523. dev/test_data/python_protobuf/test_main/concrete_class_with_enum/meta_model.py +21 -0
  524. dev/test_data/python_protobuf/test_main/concrete_class_with_list_of_instances/expected_output/pbization.py +328 -0
  525. dev/test_data/python_protobuf/test_main/concrete_class_with_list_of_instances/meta_model.py +23 -0
  526. dev/test_data/python_protobuf/test_main/concrete_class_with_primitive_attributes/expected_output/pbization.py +274 -0
  527. dev/test_data/python_protobuf/test_main/concrete_class_with_primitive_attributes/meta_model.py +41 -0
  528. dev/test_data/rdf_shacl/test_main/expected/regression_when_lang_string_class_is_missing/meta_model.py +29 -0
  529. dev/test_data/rdf_shacl/test_main/expected/regression_when_len_constraints_on_inherited_property/meta_model.py +27 -0
  530. dev/test_data/rdf_shacl/test_main/unexpected/regression_len_constraint_on_class_property/meta_model.py +61 -0
  531. dev/test_data/real_meta_models/aas_core_meta.v3.py +5721 -0
  532. dev/test_data/smoke/test_main/unexpected/infer_for_schema_error/meta_model.py +12 -0
  533. dev/test_data/smoke/test_main/unexpected/intermediate_error/meta_model.py +18 -0
  534. dev/test_data/smoke/test_main/unexpected/parse_error/meta_model.py +5 -0
  535. dev/test_data/smoke/test_main/unexpected/pattern_verification_unparsable_regex/direct_match/meta_model.py +8 -0
  536. dev/test_data/smoke/test_main/unexpected/type_error/meta_model.py +18 -0
  537. dev/tests/__init__.py +1 -0
  538. dev/tests/common.py +197 -0
  539. dev/tests/cpp/__init__.py +0 -0
  540. dev/tests/cpp/test_common.py +32 -0
  541. dev/tests/cpp/test_main.py +144 -0
  542. dev/tests/cpp/test_pattern.py +188 -0
  543. dev/tests/cpp/test_verification.py +189 -0
  544. dev/tests/cpp/test_yielding.py +225 -0
  545. dev/tests/csharp/__init__.py +0 -0
  546. dev/tests/csharp/live_test_main.py +109 -0
  547. dev/tests/csharp/test_common.py +28 -0
  548. dev/tests/csharp/test_description.py +684 -0
  549. dev/tests/csharp/test_main.py +129 -0
  550. dev/tests/csharp/test_structure.py +93 -0
  551. dev/tests/csharp/test_verification.py +82 -0
  552. dev/tests/description.py +29 -0
  553. dev/tests/golang/__init__.py +0 -0
  554. dev/tests/golang/test_common.py +78 -0
  555. dev/tests/golang/test_main.py +128 -0
  556. dev/tests/infer_for_schema/__init__.py +0 -0
  557. dev/tests/infer_for_schema/common.py +47 -0
  558. dev/tests/infer_for_schema/test_len_on_properties.py +955 -0
  559. dev/tests/infer_for_schema/test_len_on_self.py +580 -0
  560. dev/tests/infer_for_schema/test_patterns_on_properties.py +686 -0
  561. dev/tests/infer_for_schema/test_patterns_on_self.py +258 -0
  562. dev/tests/infer_for_schema/test_property_in_set_of_enumeration_literals.py +600 -0
  563. dev/tests/infer_for_schema/test_property_in_set_of_primitives.py +549 -0
  564. dev/tests/intermediate/__init__.py +0 -0
  565. dev/tests/intermediate/test_constructor.py +719 -0
  566. dev/tests/intermediate/test_hierarchy.py +221 -0
  567. dev/tests/intermediate/test_revm.py +134 -0
  568. dev/tests/intermediate/test_translate.py +337 -0
  569. dev/tests/intermediate/test_type_inference.py +333 -0
  570. dev/tests/intermediate/test_types.py +169 -0
  571. dev/tests/java/__init__.py +0 -0
  572. dev/tests/java/test_common.py +20 -0
  573. dev/tests/java/test_description.py +128 -0
  574. dev/tests/java/test_main.py +234 -0
  575. dev/tests/jsonld_context/test_main.py +79 -0
  576. dev/tests/opcua/__init__.py +3 -0
  577. dev/tests/opcua/test_main.py +110 -0
  578. dev/tests/our_jsonschema/__init__.py +3 -0
  579. dev/tests/our_jsonschema/test_main.py +232 -0
  580. dev/tests/parse/__init__.py +0 -0
  581. dev/tests/parse/test_parse.py +503 -0
  582. dev/tests/parse/test_retree.py +272 -0
  583. dev/tests/proto/__init__.py +0 -0
  584. dev/tests/proto/test_main.py +112 -0
  585. dev/tests/python/__init__.py +0 -0
  586. dev/tests/python/test_common.py +124 -0
  587. dev/tests/python/test_main.py +126 -0
  588. dev/tests/python/test_xml_playground.py +254 -0
  589. dev/tests/python_protobuf/__init__.py +0 -0
  590. dev/tests/python_protobuf/test_main.py +111 -0
  591. dev/tests/rdf_shacl/__init__.py +0 -0
  592. dev/tests/rdf_shacl/test_common.py +32 -0
  593. dev/tests/rdf_shacl/test_description.py +223 -0
  594. dev/tests/rdf_shacl/test_main.py +194 -0
  595. dev/tests/smoke/__init__.py +0 -0
  596. dev/tests/smoke/test_main.py +83 -0
  597. dev/tests/test_common.py +94 -0
  598. dev/tests/typescript/__init__.py +0 -0
  599. dev/tests/typescript/test_common.py +108 -0
  600. dev/tests/typescript/test_main.py +125 -0
  601. dev/tests/xsd/__init__.py +0 -0
  602. dev/tests/xsd/test_main.py +227 -0
  603. dev/tests/yielding/__init__.py +0 -0
  604. dev/tests/yielding/test_linear.py +558 -0
@@ -0,0 +1,2332 @@
1
+ """Generate the C++ functions to iterate over instances."""
2
+
3
+ import io
4
+ from typing import (
5
+ Optional,
6
+ Dict,
7
+ List,
8
+ Tuple,
9
+ Sequence,
10
+ Set,
11
+ Final,
12
+ FrozenSet,
13
+ )
14
+
15
+ from icontract import ensure, require
16
+
17
+ from aas_core_codegen import intermediate
18
+ from aas_core_codegen.common import (
19
+ Error,
20
+ Identifier,
21
+ assert_never,
22
+ Stripped,
23
+ indent_but_first_line,
24
+ )
25
+ from aas_core_codegen.cpp import (
26
+ common as cpp_common,
27
+ naming as cpp_naming,
28
+ yielding as cpp_yielding,
29
+ )
30
+ from aas_core_codegen.cpp.common import (
31
+ INDENT as I,
32
+ INDENT2 as II,
33
+ INDENT3 as III,
34
+ INDENT4 as IIII,
35
+ )
36
+ from aas_core_codegen.intermediate import construction as intermediate_construction
37
+ from aas_core_codegen.yielding import flow as yielding_flow
38
+
39
+
40
+ # region Check
41
+
42
+
43
+ @ensure(lambda result: not (result is not None) or (len(result) >= 1))
44
+ def _verify_that_property_enum_literals_do_not_collide(
45
+ symbol_table: intermediate.SymbolTable,
46
+ ) -> Optional[List[Error]]:
47
+ """Check that the literal names for the properties do not collied within a class."""
48
+ errors = [] # type: List[Error]
49
+
50
+ # NOTE (mristin, 2023-10-07):
51
+ # We use getter name as string representation for the enum ``Property``, so we have
52
+ # to make sure that there are no conflicts.
53
+ literal_name_to_getter_and_prop = (
54
+ dict()
55
+ ) # type: Dict[str, Tuple[str, intermediate.Property]]
56
+
57
+ for cls in symbol_table.classes:
58
+ observed_literal_names = dict() # type: Dict[str, str]
59
+ for prop in cls.properties:
60
+ literal_name = cpp_naming.enum_literal_name(prop.name)
61
+
62
+ conflicting_property_name = observed_literal_names.get(literal_name, None)
63
+
64
+ if conflicting_property_name is not None:
65
+ errors.append(
66
+ Error(
67
+ cls.parsed.node,
68
+ f"The property {prop.name!r} and "
69
+ f"the property {conflicting_property_name!r} conflict in "
70
+ f"the C++ Property literal name {literal_name!r} "
71
+ f"in class {cls.name!r}",
72
+ )
73
+ )
74
+ continue
75
+
76
+ getter = cpp_naming.getter_name(prop.name)
77
+
78
+ another_getter_and_prop = literal_name_to_getter_and_prop.get(
79
+ literal_name, None
80
+ )
81
+ if another_getter_and_prop is not None:
82
+ another_getter, another_prop = another_getter_and_prop
83
+
84
+ if another_getter != getter:
85
+ errors.append(
86
+ Error(
87
+ cls.parsed.node,
88
+ f"The property {prop.name!r} from class {cls.name!r} and "
89
+ f"the property {another_prop.name!r} "
90
+ f"from class {another_prop.specified_for.name!r} "
91
+ f"have differing getter names, "
92
+ f"{getter!r} and {another_getter!r}, respectively, "
93
+ f"for the literal in C++ enum Property {literal_name!r}",
94
+ )
95
+ )
96
+ continue
97
+ else:
98
+ literal_name_to_getter_and_prop[literal_name] = (getter, prop)
99
+
100
+ observed_literal_names[literal_name] = prop.name
101
+
102
+ if len(errors) > 0:
103
+ return errors
104
+
105
+ return None
106
+
107
+
108
+ # endregion
109
+
110
+ # region Generation
111
+
112
+
113
+ def _generate_property_enum(symbol_table: intermediate.SymbolTable) -> Stripped:
114
+ """Generate the enum which represents all the properties of all the classes."""
115
+ literal_name_set = set() # type: Set[Identifier]
116
+ for cls in symbol_table.classes:
117
+ for prop in cls.properties:
118
+ literal_name_set.add(cpp_naming.enum_literal_name(prop.name))
119
+
120
+ literal_names = sorted(literal_name_set)
121
+
122
+ literal_definitions = [
123
+ f"{literal_name} = {i}" for i, literal_name in enumerate(literal_names)
124
+ ]
125
+
126
+ literal_definitions_joined = ",\n".join(literal_definitions)
127
+
128
+ property_enum = cpp_naming.enum_name(Identifier("Property"))
129
+
130
+ return Stripped(
131
+ f"""\
132
+ /**
133
+ * Define the properties over all the classes to compactly represent the paths.
134
+ */
135
+ enum class {property_enum} : std::uint32_t {{
136
+ {I}{indent_but_first_line(literal_definitions_joined, I)}
137
+ }};"""
138
+ )
139
+
140
+
141
+ # fmt: off
142
+ @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
143
+ @ensure(
144
+ lambda result:
145
+ not (result[0] is not None) or result[0].endswith('\n'),
146
+ "Trailing newline mandatory for valid end-of-files"
147
+ )
148
+ # fmt: on
149
+ def generate_header(
150
+ symbol_table: intermediate.SymbolTable, library_namespace: Stripped
151
+ ) -> Tuple[Optional[str], Optional[List[Error]]]:
152
+ """Generate the C++ header code of the iteration functions and structures."""
153
+ collision_errors = _verify_that_property_enum_literals_do_not_collide(
154
+ symbol_table=symbol_table
155
+ )
156
+ if collision_errors is not None:
157
+ return None, collision_errors
158
+
159
+ namespace = Stripped(f"{library_namespace}::iteration")
160
+
161
+ include_guard_var = cpp_common.include_guard_var(namespace)
162
+
163
+ include_prefix_path = cpp_common.generate_include_prefix_path(library_namespace)
164
+
165
+ property_enum = cpp_naming.enum_name(Identifier("Property"))
166
+ property_to_wstring = cpp_naming.function_name(Identifier("property_to_wstring"))
167
+
168
+ blocks = [
169
+ Stripped(
170
+ f"""\
171
+ #ifndef {include_guard_var}
172
+ #define {include_guard_var}"""
173
+ ),
174
+ cpp_common.WARNING,
175
+ Stripped(
176
+ f"""\
177
+ #include "{include_prefix_path}/types.hpp"
178
+
179
+ #pragma warning(push, 0)
180
+ #include <deque>
181
+ #include <iterator>
182
+ #include <memory>
183
+ #include <string>
184
+ #pragma warning(pop)"""
185
+ ),
186
+ cpp_common.generate_namespace_opening(library_namespace),
187
+ Stripped(
188
+ """\
189
+ /**
190
+ * \\defgroup iteration Define functions and structures to iterate over instances.
191
+ * @{
192
+ */
193
+ namespace iteration {"""
194
+ ),
195
+ Stripped("// region Pathing"),
196
+ _generate_property_enum(symbol_table=symbol_table),
197
+ Stripped(
198
+ f"""\
199
+ std::wstring {property_to_wstring}(
200
+ {I}{property_enum} property
201
+ );"""
202
+ ),
203
+ Stripped(
204
+ f"""\
205
+ /**
206
+ * Represent a segment of a path to some value.
207
+ */
208
+ class ISegment {{
209
+ public:
210
+ {I}virtual std::wstring ToWstring() const = 0;
211
+ {I}virtual std::unique_ptr<ISegment> Clone() const = 0;
212
+ {I}virtual ~ISegment() = default;
213
+ }}; // class ISegment"""
214
+ ),
215
+ Stripped(
216
+ f"""\
217
+ /**
218
+ * Represent a property access on a path.
219
+ */
220
+ struct PropertySegment : public ISegment {{
221
+ {I}/**
222
+ {I} * Enumeration of the property
223
+ {I} */
224
+ {I}Property property;
225
+
226
+ {I}PropertySegment(
227
+ {II}Property a_property
228
+ {I});
229
+
230
+ {I}std::wstring ToWstring() const override;
231
+ {I}std::unique_ptr<ISegment> Clone() const override;
232
+
233
+ {I}~PropertySegment() override = default;
234
+ }}; // struct PropertySegment"""
235
+ ),
236
+ Stripped(
237
+ f"""\
238
+ /**
239
+ * Represent an index access on a path.
240
+ */
241
+ struct IndexSegment : public ISegment {{
242
+ {I}/**
243
+ {I} * Index of the item
244
+ {I} */
245
+ {I}size_t index;
246
+
247
+ {I}explicit IndexSegment(
248
+ {II}size_t an_index
249
+ {I});
250
+
251
+ {I}std::wstring ToWstring() const override;
252
+ {I}std::unique_ptr<ISegment> Clone() const override;
253
+
254
+ {I}~IndexSegment() override = default;
255
+ }}; // struct IndexSegment"""
256
+ ),
257
+ Stripped(
258
+ f"""\
259
+ /**
260
+ * \\brief Represent a path to some value.
261
+ *
262
+ * This is a path akin to C++ expressions. It is not to be confused with different
263
+ * paths used in the specification. This path class is meant to help with reporting.
264
+ * For example, we can use this path to let the user know when there is
265
+ * a verification error in a model which can concern instances, but also properties
266
+ * and items in the lists.
267
+ */
268
+ struct Path {{
269
+ {I}// NOTE (mristin):
270
+ {I}// We did not implement the reflection at the moment since we did not have a use
271
+ {I}// case for it. If you need reflection, please contact the developers. It should
272
+ {I}// be a small step going from paths to dereferencing to getters and setters.
273
+
274
+ {I}std::deque<std::unique_ptr<ISegment> > segments;
275
+
276
+ {I}Path();
277
+ {I}Path(const Path& other);
278
+ {I}Path(Path&& other);
279
+ {I}Path& operator=(const Path& other);
280
+ {I}Path& operator=(Path&& other);
281
+
282
+ {I}std::wstring ToWstring() const;
283
+ }}; // struct Path"""
284
+ ),
285
+ Stripped("// endregion Pathing"),
286
+ Stripped("// region Iterators and descent"),
287
+ Stripped(
288
+ f"""\
289
+ /// \\cond HIDDEN
290
+ namespace impl {{
291
+ class IIterator {{
292
+ public:
293
+ {I}virtual void Start() = 0;
294
+ {I}virtual void Next() = 0;
295
+ {I}virtual bool Done() const = 0;
296
+ {I}virtual const std::shared_ptr<types::IClass>& Get() const = 0;
297
+ {I}virtual long Index() const = 0;
298
+
299
+ {I}/// Prepend the segments to the path reflecting where this iterator points to.
300
+ {I}virtual void PrependToPath(Path* path) const = 0;
301
+
302
+ {I}virtual std::unique_ptr<IIterator> Clone() const = 0;
303
+
304
+ {I}virtual ~IIterator() = default;
305
+ }}; // class IIterator
306
+ }} // namespace impl
307
+ /// \\endcond"""
308
+ ),
309
+ Stripped(
310
+ f"""\
311
+ /**
312
+ * \\brief Iterate over an AAS instance.
313
+ *
314
+ * Unlike STL, this is <em>not</em> a light-weight iterator. We implement
315
+ * a "yielding" iterator by leveraging code generation so that we always keep
316
+ * the model stack as well as the properties iterated thus far.
317
+ *
318
+ * This means that copy-construction and equality comparisons are much more heavy-weight
319
+ * than you'd usually expect from an STL iterator. For example, if you want to sort
320
+ * model instances, you are most probably faster if you populate a vector, and then
321
+ * sort the vector.
322
+ *
323
+ * Also, given that this iterator is not light-weight, you should in almost all cases
324
+ * avoid the postfix increment (it++) and prefer the prefix one (++it) as the postfix
325
+ * increment would create an iterator copy every time.
326
+ *
327
+ * The value of the iterator is intentionally constant reference to a shared pointer.
328
+ * This merely means that you can not change the <em>pointer</em> while you are
329
+ * iterating. The pointed instances, however, is freely mutable. This way you can make
330
+ * further shared pointers, or include the pointed instances in other collections
331
+ * different from the original container. On the other hand, the normal case, where
332
+ * the pointer is only de-referenced, remains efficient as no copy of
333
+ * the shared pointer is created.
334
+ *
335
+ * We follow the C++ standard, and assume that comparison between the two iterators
336
+ * over two different instances results in undefined behavior. See
337
+ * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2948.html and
338
+ * https://stackoverflow.com/questions/4657513/comparing-iterators-from-different-containers.
339
+ *
340
+ * Since we use const references to shared pointers here you can also share ownership
341
+ * over instances in your own external containers. Making a copy of a shared pointer
342
+ * will automatically increase reference count, even though there is a constant
343
+ * reference. Since we do not make copies of the shared pointers, it is very important
344
+ * that the given shared pointers outlive the iteration, lest cause undefined behavior.
345
+ *
346
+ * Changing the references <em>during</em> the iteration invalidates the iterators and
347
+ * results in undefined behavior. This is similar to many of the containers in the STL,
348
+ * see: https://stackoverflow.com/questions/6438086/iterator-invalidation-rules-for-c-containers
349
+ *
350
+ * See these StackOverflow questions for performance related to shared pointers and
351
+ * constant references to shared pointers (copying <em>versus</em> referencing):
352
+ * * https://stackoverflow.com/questions/12002480/passing-stdshared-ptr-to-constructors/12002668#12002668
353
+ * * https://stackoverflow.com/questions/3310737/should-we-pass-a-shared-ptr-by-reference-or-by-value
354
+ * * https://stackoverflow.com/questions/37610494/passing-const-shared-ptrt-versus-just-shared-ptrt-as-parameter
355
+ *
356
+ * The following StackOverflow question and answers go into more detail how const-ness
357
+ * and shared pointers fit together:
358
+ * https://stackoverflow.com/questions/36271663/why-does-copying-a-const-shared-ptr-not-violate-const-ness
359
+ */
360
+ class Iterator {{
361
+ {I}using iterator_category = std::forward_iterator_tag;
362
+ {I}/// The difference is meaningless, but has to be defined.
363
+ {I}using difference_type = std::ptrdiff_t;
364
+ {I}using value_type = std::shared_ptr<types::IClass>;
365
+ {I}using pointer = const std::shared_ptr<types::IClass>*;
366
+ {I}using reference = const std::shared_ptr<types::IClass>&;
367
+
368
+ public:
369
+ {I}Iterator(const Iterator& other);
370
+ {I}Iterator(Iterator&& other);
371
+
372
+ {I}Iterator& operator=(const Iterator& other);
373
+ {I}Iterator& operator=(Iterator&& other);
374
+
375
+ {I}reference operator*() const;
376
+ {I}pointer operator->();
377
+
378
+ {I}// Prefix increment
379
+ {I}Iterator& operator++();
380
+
381
+ {I}// Postfix increment
382
+ {I}Iterator operator++(int);
383
+
384
+ {I}friend bool operator==(const Iterator& a, const Iterator& b);
385
+ {I}friend bool operator!=(const Iterator& a, const Iterator& b);
386
+
387
+ {I}friend class Descent;
388
+ {I}friend class DescentOnce;
389
+ {I}friend Path MaterializePath(const Iterator& iterator);
390
+ {I}friend void PrependToPath(const Iterator& iterator, Path* path);
391
+
392
+ private:
393
+ {I}explicit Iterator(
394
+ {II}std::unique_ptr<impl::IIterator> implementation
395
+ {I}) :
396
+ {II}implementation_(std::move(implementation)) {{
397
+ {II} // Intentionally empty.
398
+ {I}}}
399
+
400
+ {I}std::unique_ptr<impl::IIterator> implementation_;
401
+ }};"""
402
+ ),
403
+ Stripped("bool operator==(const Iterator& a, const Iterator& b);"),
404
+ Stripped("bool operator!=(const Iterator& a, const Iterator& b);"),
405
+ Stripped(
406
+ """\
407
+ /**
408
+ * \\brief Materialize the path that the \\p iterator points to.
409
+ *
410
+ * We assume that you always want a copy of the path, rather than inspect
411
+ * the path during the iteration.
412
+ *
413
+ * \\param iterator for which we want to materialize the path
414
+ * \\return Path referring to the pointed instance
415
+ */
416
+ Path MaterializePath(const Iterator& iterator);"""
417
+ ),
418
+ Stripped(
419
+ f"""\
420
+ /**
421
+ * Build a facade over an instance to iterate over instances referenced from it.
422
+ */
423
+ class IDescent {{
424
+ public:
425
+ {I}virtual Iterator begin() const = 0;
426
+ {I}virtual const Iterator& end() const = 0;
427
+ {I}virtual ~IDescent() = default;
428
+ }}; // class IDescent"""
429
+ ),
430
+ Stripped(
431
+ f"""\
432
+ /**
433
+ * \\brief Provide a recursive iterable over all the instances referenced from
434
+ * an instance.
435
+ *
436
+ * Please see the notes in the class Iterator regarding the constant reference to
437
+ * a shared pointer. In short, the instance should outlive the descent, so make
438
+ * sure you do not destroy it during the descent.
439
+ *
440
+ * Range-based loops should fit the vast majority of the use cases:
441
+ * \\code
442
+ * std::shared_ptr<types::Environment> env = ...;
443
+ * for (
444
+ * {I}const std::shared_ptr<types::IClass>& instance
445
+ * {I}: Descent(env)
446
+ * ) {{
447
+ * {I}do_something(instance);
448
+ * }}
449
+ * \\endcode
450
+ *
451
+ * \\param that instance to be iterated over recursively
452
+ * \\return Iterable over referenced instances
453
+ */
454
+ class Descent : public IDescent {{
455
+ public:
456
+ {I}Descent(
457
+ {II}std::shared_ptr<types::IClass> instance
458
+ {I});
459
+
460
+ {I}Iterator begin() const override;
461
+ {I}const Iterator& end() const override;
462
+
463
+ {I}~Descent() override = default;
464
+
465
+ private:
466
+ {I}std::shared_ptr<types::IClass> instance_;
467
+ }}; // class Descent"""
468
+ ),
469
+ Stripped(
470
+ f"""\
471
+ /**
472
+ * \\brief Provide a non-recursive iterable over the instances referenced from
473
+ * an instance.
474
+ *
475
+ * Please see the notes in the class Iterator regarding the constant reference to
476
+ * a shared pointer. In short, the instance should outlive the descent, so make
477
+ * sure you do not destroy it during the descent.
478
+ *
479
+ * Range-based loops should fit the vast majority of the use cases:
480
+ * \\code
481
+ * std::shared_ptr<types::Environment> env = ...;
482
+ * for (
483
+ * {I}const std::shared_ptr<types::IClass>& instance
484
+ * {I}: DescentOnce(env)
485
+ * ) {{
486
+ * {I}do_something(instance);
487
+ * }}
488
+ * \\endcode
489
+ */
490
+ class DescentOnce : public IDescent {{
491
+ public:
492
+ {I}DescentOnce(
493
+ {II}std::shared_ptr<types::IClass> instance
494
+ {I});
495
+
496
+ {I}Iterator begin() const override;
497
+ {I}const Iterator& end() const override;
498
+
499
+ {I}~DescentOnce() override = default;
500
+
501
+ private:
502
+ {I}std::shared_ptr<types::IClass> instance_;
503
+ }}; // class DescentOnce"""
504
+ ),
505
+ Stripped("// endregion Iterators and descent"),
506
+ ] # type: List[Stripped]
507
+
508
+ if len(symbol_table.enumerations) > 0:
509
+ blocks.append(Stripped("// region Over enumerations"))
510
+
511
+ for enum in symbol_table.enumerations:
512
+ enum_name = cpp_naming.enum_name(enum.name)
513
+ over_enum = cpp_naming.constant_name(Identifier(f"over_{enum.name}"))
514
+
515
+ blocks.append(
516
+ Stripped(
517
+ f"""\
518
+ /**
519
+ * \\brief Give a container for all the literals of types::{enum_name}.
520
+ *
521
+ * This container is practical when you want to show the literals in a GUI or a CLI.
522
+ */
523
+ extern const std::vector<types::{enum_name}> {over_enum};"""
524
+ )
525
+ )
526
+
527
+ blocks.append(Stripped("// endregion Over enumerations"))
528
+
529
+ blocks.extend(
530
+ [
531
+ Stripped(
532
+ """\
533
+ } // namespace iteration
534
+ /**@}*/"""
535
+ ),
536
+ cpp_common.generate_namespace_closing(library_namespace),
537
+ cpp_common.WARNING,
538
+ Stripped(f"#endif // {include_guard_var}"),
539
+ ]
540
+ )
541
+
542
+ out = io.StringIO()
543
+ for i, block in enumerate(blocks):
544
+ if i > 0:
545
+ out.write("\n\n")
546
+
547
+ out.write(block)
548
+
549
+ out.write("\n")
550
+
551
+ return out.getvalue(), None
552
+
553
+
554
+ def _generate_property_to_wstring_implementation(
555
+ symbol_table: intermediate.SymbolTable,
556
+ ) -> Stripped:
557
+ """Generate the implementation of the stringification for ``Property`` enum."""
558
+ literal_name_to_getter = dict() # type: Dict[Identifier, Identifier]
559
+ literal_name_set = set() # type: Set[Identifier]
560
+
561
+ for cls in symbol_table.classes:
562
+ for prop in cls.properties:
563
+ literal_name = cpp_naming.enum_literal_name(prop.name)
564
+ literal_name_to_getter[literal_name] = cpp_naming.getter_name(prop.name)
565
+
566
+ literal_name_set.add(literal_name)
567
+
568
+ literal_names = sorted(literal_name_set)
569
+
570
+ property_enum = cpp_naming.enum_name(Identifier("Property"))
571
+
572
+ case_blocks = [] # type: List[Stripped]
573
+ for literal_name in literal_names:
574
+ getter = literal_name_to_getter[literal_name]
575
+
576
+ case_blocks.append(
577
+ Stripped(
578
+ f"""\
579
+ case {property_enum}::{literal_name}:
580
+ {I}return {cpp_common.wstring_literal(getter)};"""
581
+ )
582
+ )
583
+
584
+ case_blocks.append(
585
+ Stripped(
586
+ f"""\
587
+ default:
588
+ {I}throw std::invalid_argument(
589
+ {II}common::Concat(
590
+ {III}"Unexpected property literal: ",
591
+ {III}std::to_string(
592
+ {IIII}static_cast<std::uint32_t>(property)
593
+ {III})
594
+ {II})
595
+ {I});"""
596
+ )
597
+ )
598
+
599
+ case_blocks_joined = "\n".join(case_blocks)
600
+
601
+ property_to_wstring = cpp_naming.function_name(Identifier("property_to_wstring"))
602
+
603
+ return Stripped(
604
+ f"""\
605
+ /**
606
+ * Translate the enumeration literal \\p property to text.
607
+ *
608
+ * \\param property to be converted into text
609
+ * \\return text representation of \\p property
610
+ * \\throw std::invalid_argument if \\p property invalid
611
+ */
612
+ std::wstring {property_to_wstring}(
613
+ {I}Property property
614
+ ) {{
615
+ {I}switch (property) {{
616
+ {II}{indent_but_first_line(case_blocks_joined, II)}
617
+ {I}}}
618
+ }} // function to_wstring"""
619
+ )
620
+
621
+
622
+ def _generate_property_segment_implementation() -> List[Stripped]:
623
+ """Generate the implementation of ``PropertySegment`` struct."""
624
+ property_to_wstring = cpp_naming.function_name(Identifier("property_to_wstring"))
625
+
626
+ return [
627
+ Stripped("// region struct PropertySegment"),
628
+ Stripped(
629
+ f"""\
630
+ PropertySegment::PropertySegment(Property a_property) {{
631
+ {I}property = a_property;
632
+ }}"""
633
+ ),
634
+ Stripped(
635
+ f"""\
636
+ std::wstring PropertySegment::ToWstring() const {{
637
+ {I}return common::Concat(
638
+ {II}L".",
639
+ {II}{property_to_wstring}(property)
640
+ {I});
641
+ }}"""
642
+ ),
643
+ Stripped(
644
+ f"""\
645
+ std::unique_ptr<ISegment> PropertySegment::Clone() const {{
646
+ {I}return common::make_unique<PropertySegment>(*this);
647
+ }}"""
648
+ ),
649
+ Stripped("// endregion struct PropertySegment"),
650
+ ]
651
+
652
+
653
+ def _generate_index_segment_implementation() -> List[Stripped]:
654
+ """Generate the implementation of ``IndexSegment`` struct."""
655
+ return [
656
+ Stripped("// region struct IndexSegment"),
657
+ Stripped(
658
+ f"""\
659
+ IndexSegment::IndexSegment(size_t an_index) {{
660
+ {I}index = an_index;
661
+ }}"""
662
+ ),
663
+ Stripped(
664
+ f"""\
665
+ std::wstring IndexSegment::ToWstring() const {{
666
+ {I}return common::Concat(
667
+ {II}L"[",
668
+ {II}std::to_wstring(index),
669
+ {II}L"]"
670
+ {I});
671
+ }}"""
672
+ ),
673
+ Stripped(
674
+ f"""\
675
+ std::unique_ptr<ISegment> IndexSegment::Clone() const {{
676
+ {I}return common::make_unique<IndexSegment>(*this);
677
+ }}"""
678
+ ),
679
+ Stripped("// endregion struct IndexSegment"),
680
+ ]
681
+
682
+
683
+ def _generate_path_implementation() -> List[Stripped]:
684
+ """Generate the implementation of the ``Path`` struct."""
685
+ return [
686
+ Stripped("// region struct Path"),
687
+ Stripped(
688
+ f"""\
689
+ Path::Path() {{
690
+ {I}// Intentionally empty.
691
+ }}"""
692
+ ),
693
+ Stripped(
694
+ f"""\
695
+ Path::Path(const Path& other) {{
696
+ {I}for (const std::unique_ptr<ISegment>& segment : other.segments) {{
697
+ {II}segments.emplace_back(segment->Clone());
698
+ {I}}}
699
+ }}"""
700
+ ),
701
+ Stripped(
702
+ f"""\
703
+ Path::Path(Path&& other) {{
704
+ {I}segments = std::move(other.segments);
705
+ }}"""
706
+ ),
707
+ Stripped(
708
+ f"""\
709
+ Path& Path::operator=(const Path& other) {{
710
+ {I}segments.clear();
711
+ {I}for (const std::unique_ptr<ISegment>& segment : other.segments) {{
712
+ {II}segments.emplace_back(segment->Clone());
713
+ {I}}}
714
+ {I}return *this;
715
+ }}"""
716
+ ),
717
+ Stripped(
718
+ f"""\
719
+ Path& Path::operator=(Path&& other) {{
720
+ {I}if (this != &other) {{
721
+ {II}segments = std::move(other.segments);
722
+ {I}}}
723
+ {I}return *this;
724
+ }}"""
725
+ ),
726
+ Stripped(
727
+ f"""\
728
+ std::wstring Path::ToWstring() const {{
729
+ {I}std::vector<std::wstring> parts;
730
+ {I}parts.reserve(segments.size());
731
+
732
+ {I}for (const std::unique_ptr<ISegment>& segment : segments ) {{
733
+ {II}parts.emplace_back(segment->ToWstring());
734
+ {I}}}
735
+
736
+ {I}size_t size = 0;
737
+ {I}for (const std::wstring& part : parts) {{
738
+ {II}size += part.size();
739
+ {I}}}
740
+
741
+ {I}std::wstring result;
742
+ {I}result.reserve(size);
743
+ {I}for (const std::wstring& part : parts) {{
744
+ {II}result.append(part);
745
+ {I}}}
746
+
747
+ {I}return result;
748
+ }}"""
749
+ ),
750
+ Stripped("// endregion struct Path"),
751
+ ]
752
+
753
+
754
+ class IteratorQualities:
755
+ """Query the qualities of a non-recursive iterator corresponding to a class."""
756
+
757
+ #: The class corresponding to the iterator
758
+ cls: Final[intermediate.ConcreteClass]
759
+
760
+ #: The properties which should be iterated over
761
+ relevant_properties: Final[Sequence[intermediate.Property]]
762
+
763
+ #: A set of Python IDs of the relevant properties
764
+ relevant_property_id_set: Final[FrozenSet[int]]
765
+
766
+ #: Set if the class contains a property which is a list of instances
767
+ cls_contains_a_list_property: Final[bool]
768
+
769
+ def __init__(self, cls: intermediate.ConcreteClass) -> None:
770
+ """Initialize with the given class."""
771
+ relevant_properties = [] # type: List[intermediate.Property]
772
+
773
+ cls_contains_a_list_property = False
774
+
775
+ for prop in cls.properties:
776
+ type_anno = intermediate.beneath_optional(prop.type_annotation)
777
+
778
+ if isinstance(type_anno, intermediate.OurTypeAnnotation) and isinstance(
779
+ type_anno.our_type,
780
+ (intermediate.AbstractClass, intermediate.ConcreteClass),
781
+ ):
782
+ relevant_properties.append(prop)
783
+
784
+ elif isinstance(type_anno, intermediate.ListTypeAnnotation):
785
+ assert isinstance(
786
+ type_anno.items, intermediate.OurTypeAnnotation
787
+ ) and isinstance(
788
+ type_anno.items.our_type,
789
+ (intermediate.AbstractClass, intermediate.ConcreteClass),
790
+ ), (
791
+ f"NOTE (mristin, 2023-09-27): We expect only lists of classes "
792
+ f"at the moment, but you specified {prop.type_annotation} "
793
+ f"in class {cls.name!r} and property {prop.name!r}. "
794
+ f"Please contact the developers if you need this feature."
795
+ )
796
+
797
+ cls_contains_a_list_property = True
798
+
799
+ relevant_properties.append(prop)
800
+ else:
801
+ pass
802
+
803
+ self.cls = cls
804
+ self.relevant_properties = relevant_properties
805
+ self.relevant_property_id_set = frozenset(
806
+ id(prop) for prop in self.relevant_properties
807
+ )
808
+ self.cls_contains_a_list_property = cls_contains_a_list_property
809
+
810
+
811
+ @require(lambda iterator_qualities: len(iterator_qualities.relevant_properties) == 0)
812
+ def _generate_empty_iterator_over_cls(
813
+ iterator_qualities: IteratorQualities,
814
+ ) -> List[Stripped]:
815
+ """Generate the iterator over a class with no references to other instances."""
816
+ interface_name = cpp_naming.interface_name(iterator_qualities.cls.name)
817
+ iterator_over_cls = cpp_naming.class_name(
818
+ Identifier(f"Iterator_over_{iterator_qualities.cls.name}")
819
+ )
820
+
821
+ return [
822
+ Stripped(
823
+ f"""\
824
+ /**
825
+ * This iterator is always done as {interface_name}
826
+ * references no other instances.
827
+ */
828
+ class {iterator_over_cls} : public impl::IIterator {{
829
+ public:
830
+ {I}{iterator_over_cls}(
831
+ {II}const std::shared_ptr<types::IClass>&
832
+ {I}) {{
833
+ {II}// Intentionally empty.
834
+ {I}}}
835
+
836
+ {I}void Start() override {{
837
+ {II}// Intentionally empty.
838
+ {I}}}
839
+
840
+ {I}void Next() override {{
841
+ {II}throw std::logic_error(
842
+ {III}"You want to move "
843
+ {III}"an {iterator_over_cls}, "
844
+ {III}"but the iterator is always done as "
845
+ {III}"{interface_name} "
846
+ {III}"references no other instances."
847
+ {II});
848
+ {I}}}
849
+
850
+ {I}bool Done() const override {{
851
+ {II}return true;
852
+ {I}}}
853
+
854
+ {I}const std::shared_ptr<types::IClass>& Get() const override {{
855
+ {II}throw std::logic_error(
856
+ {III}"You want to get from an {iterator_over_cls}, "
857
+ {III}"but the iterator is always done as "
858
+ {III}"{interface_name} references "
859
+ {III}"no other instances."
860
+ {II});
861
+ {I}}}
862
+
863
+ {I}long Index() const override {{
864
+ {II}return -1;
865
+ {I}}}
866
+
867
+ {I}std::unique_ptr<impl::IIterator> Clone() const override {{
868
+ {II}return common::make_unique<{iterator_over_cls}>(*this);
869
+ {I}}}
870
+
871
+ {I}void PrependToPath(Path*) const override {{
872
+ {II}throw std::logic_error(
873
+ {III}"You want to prepend to path from an {iterator_over_cls}, "
874
+ {III}"but the iterator is always done as "
875
+ {III}"{interface_name} references "
876
+ {III}"no other instances."
877
+ {II});
878
+ {I}}}
879
+
880
+ {I}~{iterator_over_cls}() override = default;
881
+ }}; // class {iterator_over_cls}"""
882
+ )
883
+ ]
884
+
885
+
886
+ @require(lambda iterator_qualities: len(iterator_qualities.relevant_properties) > 0)
887
+ def _generate_iterator_over_cls_execute_implementation(
888
+ iterator_qualities: IteratorQualities,
889
+ ) -> Stripped:
890
+ """Generate the implementation of ``Execute()`` member."""
891
+ cls = iterator_qualities.cls
892
+
893
+ flow = [
894
+ yielding_flow.command_from_text(
895
+ """\
896
+ property_.reset();
897
+ item_ = nullptr;
898
+ index_ = -1;
899
+ done_ = false;"""
900
+ )
901
+ ] # type: List[yielding_flow.Node]
902
+
903
+ if iterator_qualities.cls_contains_a_list_property:
904
+ flow.append(yielding_flow.command_from_text("cursor_.reset();"))
905
+
906
+ for prop in iterator_qualities.relevant_properties:
907
+ type_anno = intermediate.beneath_optional(prop.type_annotation)
908
+
909
+ getter_name = cpp_naming.getter_name(prop.name)
910
+ property_literal = cpp_naming.enum_literal_name(prop.name)
911
+
912
+ if isinstance(type_anno, intermediate.OurTypeAnnotation) and isinstance(
913
+ type_anno.our_type, (intermediate.AbstractClass, intermediate.ConcreteClass)
914
+ ):
915
+ if isinstance(prop.type_annotation, intermediate.OptionalTypeAnnotation):
916
+ flow.append(
917
+ yielding_flow.IfTrue(
918
+ f"casted_->{getter_name}().has_value()",
919
+ [
920
+ yielding_flow.command_from_text(
921
+ f"""\
922
+ property_ = Property::{property_literal};
923
+ item_ = std::move(
924
+ {I}std::static_pointer_cast<types::IClass>(
925
+ {II}*(casted_->{getter_name}())
926
+ {I})
927
+ );
928
+ ++index_;"""
929
+ ),
930
+ yielding_flow.Yield(),
931
+ ],
932
+ )
933
+ )
934
+ else:
935
+ flow.append(
936
+ yielding_flow.command_from_text(
937
+ f"""\
938
+ property_ = Property::{property_literal};
939
+ item_ = std::move(
940
+ {I}std::static_pointer_cast<types::IClass>(
941
+ {II}casted_->{getter_name}()
942
+ {I})
943
+ );
944
+ ++index_;"""
945
+ )
946
+ )
947
+ flow.append(yielding_flow.Yield())
948
+
949
+ elif isinstance(type_anno, intermediate.ListTypeAnnotation):
950
+ assert isinstance(
951
+ type_anno.items, intermediate.OurTypeAnnotation
952
+ ) and isinstance(
953
+ type_anno.items.our_type,
954
+ (intermediate.AbstractClass, intermediate.ConcreteClass),
955
+ ), (
956
+ f"NOTE (mristin, 2023-09-27): We expect only lists of classes "
957
+ f"at the moment, but you specified {prop.type_annotation} "
958
+ f"in class {cls.name!r} and property {prop.name!r}. "
959
+ f"Please contact the developers if you need this feature."
960
+ )
961
+
962
+ if isinstance(prop.type_annotation, intermediate.OptionalTypeAnnotation):
963
+ list_type = cpp_common.generate_type_with_const_ref_if_applicable(
964
+ type_annotation=prop.type_annotation.value,
965
+ types_namespace=cpp_common.TYPES_NAMESPACE,
966
+ )
967
+ list_var = cpp_naming.variable_name(Identifier(f"the_{prop.name}"))
968
+
969
+ flow.append(
970
+ yielding_flow.IfTrue(
971
+ f"casted_->{getter_name}().has_value()",
972
+ [
973
+ yielding_flow.command_from_text(
974
+ f"property_ = Property::{property_literal};"
975
+ ),
976
+ yielding_flow.For(
977
+ f"*cursor_ < casted_->{getter_name}()->size()",
978
+ "++(*cursor_);",
979
+ [
980
+ yielding_flow.command_from_text(
981
+ f"""\
982
+ {list_type} {list_var}(
983
+ {I}*(casted_->{getter_name}())
984
+ );
985
+
986
+ item_ = std::move(
987
+ {I}std::static_pointer_cast<types::IClass>(
988
+ {II}{list_var}[*cursor_]
989
+ {I})
990
+ );
991
+ ++index_;"""
992
+ ),
993
+ yielding_flow.Yield(),
994
+ ],
995
+ init="cursor_ = 0;",
996
+ ),
997
+ yielding_flow.command_from_text("cursor_.reset();"),
998
+ ],
999
+ )
1000
+ )
1001
+ else:
1002
+ list_type = cpp_common.generate_type_with_const_ref_if_applicable(
1003
+ type_annotation=prop.type_annotation,
1004
+ types_namespace=cpp_common.TYPES_NAMESPACE,
1005
+ )
1006
+ list_var = cpp_naming.variable_name(Identifier(f"the_{prop.name}"))
1007
+
1008
+ flow.append(
1009
+ yielding_flow.command_from_text(
1010
+ f"property_ = Property::{property_literal};"
1011
+ )
1012
+ )
1013
+ flow.append(
1014
+ yielding_flow.For(
1015
+ f"*cursor_ < casted_->{getter_name}().size()",
1016
+ "++(*cursor_);",
1017
+ [
1018
+ yielding_flow.command_from_text(
1019
+ f"""\
1020
+ {list_type} {list_var}(
1021
+ {I}casted_->{getter_name}()
1022
+ );
1023
+
1024
+ item_ = std::move(
1025
+ {I}std::static_pointer_cast<types::IClass>(
1026
+ {II}{list_var}[*cursor_]
1027
+ {I})
1028
+ );
1029
+ ++index_;"""
1030
+ ),
1031
+ yielding_flow.Yield(),
1032
+ ],
1033
+ init="cursor_ = 0;",
1034
+ )
1035
+ )
1036
+ flow.append(yielding_flow.command_from_text("cursor_.reset();"))
1037
+
1038
+ flow.append(
1039
+ yielding_flow.command_from_text(
1040
+ """\
1041
+ done_ = true;
1042
+ index_ = -1;"""
1043
+ )
1044
+ )
1045
+
1046
+ body = cpp_yielding.generate_execute_body(
1047
+ flow=flow, state_member=Identifier("state_")
1048
+ )
1049
+
1050
+ iterator_name = cpp_naming.class_name(Identifier(f"Iterator_over_{cls.name}"))
1051
+
1052
+ return Stripped(
1053
+ f"""\
1054
+ void {iterator_name}::Execute() {{
1055
+ {I}{indent_but_first_line(body, I)}
1056
+ }}"""
1057
+ )
1058
+
1059
+
1060
+ @require(lambda iterator_qualities: len(iterator_qualities.relevant_properties) > 0)
1061
+ def _generate_iterator_over_cls(
1062
+ iterator_qualities: IteratorQualities,
1063
+ ) -> List[Stripped]:
1064
+ """Generate a non-recursive iterator over referenced instances."""
1065
+ cls = iterator_qualities.cls
1066
+
1067
+ iterator_name = cpp_naming.class_name(Identifier(f"Iterator_over_{cls.name}"))
1068
+
1069
+ interface_name = cpp_naming.interface_name(cls.name)
1070
+
1071
+ private_properties = [
1072
+ Stripped(
1073
+ """\
1074
+ // We make instance_ a pointer, so that we can follow the rule-of-zero.
1075
+ const std::shared_ptr<types::IClass>* instance_;"""
1076
+ ),
1077
+ Stripped(
1078
+ f"""\
1079
+ // We make casted_ a pointer, so that we can follow the rule-of-zero.
1080
+ const types::{interface_name}* casted_;"""
1081
+ ),
1082
+ Stripped("std::uint32_t state_;"),
1083
+ Stripped("common::optional<Property> property_;"),
1084
+ ]
1085
+ if iterator_qualities.cls_contains_a_list_property:
1086
+ private_properties.append(
1087
+ Stripped("common::optional<size_t> cursor_; // in yield-from loops")
1088
+ )
1089
+
1090
+ private_properties.extend(
1091
+ (
1092
+ Stripped("std::shared_ptr<types::IClass> item_;"),
1093
+ Stripped("long index_; // in total iteration"),
1094
+ Stripped("bool done_;"),
1095
+ )
1096
+ )
1097
+
1098
+ private_properties_joined = "\n".join(private_properties)
1099
+
1100
+ execute_block = _generate_iterator_over_cls_execute_implementation(
1101
+ iterator_qualities=iterator_qualities
1102
+ )
1103
+
1104
+ if iterator_qualities.cls_contains_a_list_property:
1105
+ prepend_to_path_block = Stripped(
1106
+ f"""\
1107
+ void {iterator_name}::PrependToPath(
1108
+ {I}Path* path
1109
+ ) const {{
1110
+ {I}#ifdef DEBUG
1111
+ {I}if (Done()) {{
1112
+ {II}throw std::logic_error(
1113
+ {III}"You want to prepend to path from {iterator_name}, "
1114
+ {III}"but the iterator was done."
1115
+ {II});
1116
+ {I}}}
1117
+ {I}#endif
1118
+
1119
+ {I}if (cursor_.has_value()) {{
1120
+ {II}path->segments.emplace_front(
1121
+ {III}common::make_unique<IndexSegment>(*cursor_)
1122
+ {II});
1123
+ {I}}}
1124
+
1125
+ {I}#ifdef DEBUG
1126
+ {I}if (!property_.has_value()) {{
1127
+ {II}throw std::logic_error(
1128
+ {III}"You want to prepend to path from {iterator_name}, "
1129
+ {III}"but the property_ has not been set to a value."
1130
+ {II});
1131
+ {I}}}
1132
+ {I}#endif
1133
+
1134
+ {I}path->segments.emplace_front(
1135
+ {II}common::make_unique<PropertySegment>(*property_)
1136
+ {I});
1137
+ }}"""
1138
+ )
1139
+
1140
+ else:
1141
+ prepend_to_path_block = Stripped(
1142
+ f"""\
1143
+ void {iterator_name}::PrependToPath(
1144
+ {I}Path* path
1145
+ ) const {{
1146
+ {I}#ifdef DEBUG
1147
+ {I}if (Done()) {{
1148
+ {II}throw std::logic_error(
1149
+ {III}"You want to prepend to path from {iterator_name}, "
1150
+ {III}"but the iterator was done."
1151
+ {II});
1152
+ {I}}}
1153
+
1154
+ {I}if (!property_.has_value()) {{
1155
+ {II}throw std::logic_error(
1156
+ {III}"You want to prepend to path from {iterator_name}, "
1157
+ {III}"but the property_ has not been set to a value."
1158
+ {II});
1159
+ {I}}}
1160
+ {I}#endif
1161
+
1162
+ {I}path->segments.emplace_front(
1163
+ {II}common::make_unique<PropertySegment>(*property_)
1164
+ {I});
1165
+ }}"""
1166
+ )
1167
+
1168
+ return [
1169
+ Stripped(
1170
+ f"""\
1171
+ /**
1172
+ * Iterate non-recursively over the instances referenced from an instance.
1173
+ */
1174
+ class {iterator_name} : public impl::IIterator {{
1175
+ public:
1176
+ {I}{iterator_name}(
1177
+ {II}const std::shared_ptr<types::IClass>& instance
1178
+ {I});
1179
+ {I}void Start() override;
1180
+ {I}void Next() override;
1181
+ {I}bool Done() const override;
1182
+ {I}const std::shared_ptr<types::IClass>& Get() const override;
1183
+ {I}long Index() const override;
1184
+ {I}void PrependToPath(Path* path) const override;
1185
+ {I}std::unique_ptr<impl::IIterator> Clone() const override;
1186
+ {I}~{iterator_name}() override = default;
1187
+
1188
+ private:
1189
+ {I}{indent_but_first_line(private_properties_joined, I)}
1190
+
1191
+ {I}void Execute();
1192
+ }}; // class {iterator_name}"""
1193
+ ),
1194
+ Stripped(
1195
+ f"""\
1196
+ {iterator_name}::{iterator_name}(
1197
+ {I}const std::shared_ptr<types::IClass>& instance
1198
+ ) :
1199
+ {I}instance_(&instance),
1200
+ {I}// NOTE (mristin):
1201
+ {I}// The dynamic cast is necessary due to virtual inheritance. Otherwise,
1202
+ {I}// we would have used static cast.
1203
+ {I}casted_(
1204
+ {II}dynamic_cast<types::{interface_name}*>(
1205
+ {III}instance.get()
1206
+ {II})
1207
+ {I}) {{
1208
+ {I}// Intentionally empty.
1209
+ }}"""
1210
+ ),
1211
+ Stripped(
1212
+ f"""\
1213
+ void {iterator_name}::Start() {{
1214
+ {I}state_ = 0;
1215
+ {I}Execute();
1216
+ }}"""
1217
+ ),
1218
+ Stripped(
1219
+ f"""\
1220
+ void {iterator_name}::Next() {{
1221
+ {I}#ifdef DEBUG
1222
+ {I}if (Done()) {{
1223
+ {II}throw std::logic_error(
1224
+ {III}"You want to move {iterator_name}, "
1225
+ {III}"but it was done."
1226
+ {II});
1227
+ {I}}}
1228
+ {I}#endif
1229
+
1230
+ {I}Execute();
1231
+ }}"""
1232
+ ),
1233
+ Stripped(
1234
+ f"""\
1235
+ bool {iterator_name}::Done() const {{
1236
+ {I}return done_;
1237
+ }}"""
1238
+ ),
1239
+ Stripped(
1240
+ f"""\
1241
+ const std::shared_ptr<types::IClass>& {iterator_name}::Get() const {{
1242
+ {I}#ifdef DEBUG
1243
+ {I}if (Done()) {{
1244
+ {II}throw std::logic_error(
1245
+ {III}"You want to get from {iterator_name}, "
1246
+ {III}"but the iterator was done."
1247
+ {II});
1248
+ {I}}}
1249
+ {I}#endif
1250
+
1251
+ {I}return item_;
1252
+ }}"""
1253
+ ),
1254
+ Stripped(
1255
+ f"""\
1256
+ long {iterator_name}::Index() const {{
1257
+ {I}#ifdef DEBUG
1258
+ {I}if (Done() && index_ != -1) {{
1259
+ {II}throw std::logic_error(
1260
+ {III}common::Concat(
1261
+ {IIII}"Expected index to be -1 "
1262
+ {IIII}"from a done {iterator_name}, "
1263
+ {IIII}"but got: ",
1264
+ {IIII}std::to_string(index_)
1265
+ {III})
1266
+ {II});
1267
+ {I}}}
1268
+ {I}#endif
1269
+
1270
+ {I}return index_;
1271
+ }}"""
1272
+ ),
1273
+ prepend_to_path_block,
1274
+ Stripped(
1275
+ f"""\
1276
+ std::unique_ptr<impl::IIterator> {iterator_name}::Clone() const {{
1277
+ {I}return common::make_unique<{iterator_name}>(*this);
1278
+ }}"""
1279
+ ),
1280
+ execute_block,
1281
+ ]
1282
+
1283
+
1284
+ def _generate_iteration_over_cls(cls: intermediate.ConcreteClass) -> List[Stripped]:
1285
+ """Generate the iterator over the given class."""
1286
+ iterator_qualities = IteratorQualities(cls=cls)
1287
+
1288
+ if len(iterator_qualities.relevant_properties) == 0:
1289
+ return _generate_empty_iterator_over_cls(iterator_qualities=iterator_qualities)
1290
+
1291
+ interface_name = cpp_naming.interface_name(cls.name)
1292
+
1293
+ return [
1294
+ Stripped(f"// region Non-recursive iteration over {interface_name}"),
1295
+ *_generate_iterator_over_cls(iterator_qualities=iterator_qualities),
1296
+ Stripped("// endregion"),
1297
+ ]
1298
+
1299
+
1300
+ def _generate_new_non_recursive_iterator_function(
1301
+ symbol_table: intermediate.SymbolTable,
1302
+ ) -> Stripped:
1303
+ """Generate the factory for non-recursive iterators."""
1304
+ case_blocks = [] # type: List[Stripped]
1305
+
1306
+ for cls in symbol_table.concrete_classes:
1307
+ enum_name = cpp_naming.enum_name(Identifier("Model_type"))
1308
+ literal_name = cpp_naming.enum_literal_name(cls.name)
1309
+
1310
+ iterator_over_cls = cpp_naming.class_name(
1311
+ Identifier(f"Iterator_over_{cls.name}")
1312
+ )
1313
+
1314
+ case_blocks.append(
1315
+ Stripped(
1316
+ f"""\
1317
+ case types::{enum_name}::{literal_name}:
1318
+ {I}return common::make_unique<{iterator_over_cls}>(
1319
+ {II}instance
1320
+ {I});"""
1321
+ )
1322
+ )
1323
+
1324
+ case_blocks.append(
1325
+ Stripped(
1326
+ f"""\
1327
+ default:
1328
+ {I}throw std::logic_error(
1329
+ {II}common::Concat(
1330
+ {III}"Unexpected model type: ",
1331
+ {III}std::to_string(
1332
+ {IIII}static_cast<std::uint32_t>(instance->model_type())
1333
+ {III})
1334
+ {II})
1335
+ {I});"""
1336
+ )
1337
+ )
1338
+
1339
+ case_blocks_joined = "\n".join(case_blocks)
1340
+
1341
+ switch_stmt = Stripped(
1342
+ f"""\
1343
+ switch (instance->model_type()) {{
1344
+ {I}{indent_but_first_line(case_blocks_joined, I)}
1345
+ }}"""
1346
+ )
1347
+
1348
+ new_non_recursive_iterator = cpp_naming.function_name(
1349
+ Identifier("new_non_recursive_iterator")
1350
+ )
1351
+
1352
+ return Stripped(
1353
+ f"""\
1354
+ /**
1355
+ * Produce a non-recursive iterator over the instance given its runtime model type.
1356
+ */
1357
+ std::unique_ptr<impl::IIterator> {new_non_recursive_iterator}(
1358
+ {I}const std::shared_ptr<types::IClass>& instance
1359
+ ) {{
1360
+ {I}{indent_but_first_line(switch_stmt, I)}
1361
+ }}"""
1362
+ )
1363
+
1364
+
1365
+ def _generate_recursive_inclusive_iterator_execute() -> Stripped:
1366
+ """Generate the ``Execute()`` method of the recursive inclusive iterator."""
1367
+ new_non_recursive_iterator = cpp_naming.function_name(
1368
+ Identifier("new_non_recursive_iterator")
1369
+ )
1370
+
1371
+ flow = [
1372
+ yielding_flow.command_from_text(
1373
+ """\
1374
+ item_ = instance_;
1375
+ index_ = 0;
1376
+ done_ = false;
1377
+ non_recursive_iterator_.reset(nullptr);
1378
+ recursive_iterator_.reset(nullptr);"""
1379
+ ),
1380
+ yielding_flow.Yield(),
1381
+ yielding_flow.command_from_text(
1382
+ f"""\
1383
+ non_recursive_iterator_ = {new_non_recursive_iterator}(
1384
+ {I}*instance_
1385
+ );"""
1386
+ ),
1387
+ yielding_flow.For(
1388
+ "!non_recursive_iterator_->Done()",
1389
+ "non_recursive_iterator_->Next();",
1390
+ [
1391
+ yielding_flow.command_from_text(
1392
+ """\
1393
+ item_ = &(non_recursive_iterator_->Get());
1394
+ ++index_;"""
1395
+ ),
1396
+ yielding_flow.Yield(),
1397
+ yielding_flow.command_from_text(
1398
+ f"""\
1399
+ recursive_iterator_ = std::move(
1400
+ {I}common::make_unique<RecursiveExclusiveIterator>(
1401
+ {II}*item_
1402
+ {I})
1403
+ );"""
1404
+ ),
1405
+ yielding_flow.For(
1406
+ "!recursive_iterator_->Done()",
1407
+ "recursive_iterator_->Next();",
1408
+ [
1409
+ yielding_flow.command_from_text(
1410
+ """\
1411
+ item_ = &(recursive_iterator_->Get());
1412
+ ++index_;"""
1413
+ ),
1414
+ yielding_flow.Yield(),
1415
+ ],
1416
+ init="recursive_iterator_->Start();",
1417
+ ),
1418
+ yielding_flow.command_from_text("recursive_iterator_.reset(nullptr);"),
1419
+ ],
1420
+ init="non_recursive_iterator_->Start();",
1421
+ ),
1422
+ yielding_flow.command_from_text(
1423
+ """\
1424
+ non_recursive_iterator_.reset(nullptr);
1425
+ done_ = true;
1426
+ index_ = -1;"""
1427
+ ),
1428
+ ] # type: List[yielding_flow.Node]
1429
+
1430
+ body = cpp_yielding.generate_execute_body(
1431
+ flow=flow, state_member=Identifier("state_")
1432
+ )
1433
+
1434
+ return Stripped(
1435
+ f"""\
1436
+ void RecursiveInclusiveIterator::Execute() {{
1437
+ {I}{indent_but_first_line(body, I)}
1438
+ }}"""
1439
+ )
1440
+
1441
+
1442
+ def _generate_recursive_iteration() -> List[Stripped]:
1443
+ """Generate the iterator to recursively iterate over the referenced instances."""
1444
+ execute_block = _generate_recursive_inclusive_iterator_execute()
1445
+
1446
+ return [
1447
+ Stripped(
1448
+ f"""\
1449
+ /**
1450
+ * Iterate recursively over the instance, including the instance in the iteration.
1451
+ *
1452
+ * This is a realisation of the following pseudo-code:
1453
+ * \\code
1454
+ * stack = new Stack();
1455
+ * stack.push(instance);
1456
+ * while not stack.empty():
1457
+ * instance = stack.pop()
1458
+ * yield instance
1459
+ *
1460
+ * it = new_non_recursive_iterator(instance)
1461
+ * while not it.done():
1462
+ * yield recursively from it.get()
1463
+ * it.next()
1464
+ * \\endcode
1465
+ */
1466
+ class RecursiveInclusiveIterator : public impl::IIterator {{
1467
+ public:
1468
+ {I}RecursiveInclusiveIterator(
1469
+ {II}const std::shared_ptr<types::IClass>& instance
1470
+ {I});
1471
+
1472
+ {I}RecursiveInclusiveIterator(
1473
+ {II}const RecursiveInclusiveIterator& other
1474
+ {I});
1475
+ {I}RecursiveInclusiveIterator(
1476
+ {II}RecursiveInclusiveIterator&& other
1477
+ {I});
1478
+ {I}RecursiveInclusiveIterator& operator=(
1479
+ {II}const RecursiveInclusiveIterator& other
1480
+ {I});
1481
+ {I}RecursiveInclusiveIterator& operator=(
1482
+ {II}RecursiveInclusiveIterator&& other
1483
+ {I});
1484
+
1485
+ {I}void Start() override;
1486
+ {I}void Next() override;
1487
+ {I}bool Done() const override;
1488
+ {I}const std::shared_ptr<types::IClass>& Get() const override;
1489
+ {I}long Index() const override;
1490
+ {I}void PrependToPath(Path* path) const override;
1491
+ {I}std::unique_ptr<impl::IIterator> Clone() const override;
1492
+ {I}~RecursiveInclusiveIterator() override = default;
1493
+
1494
+ private:
1495
+ {I}// The instance_ needs to be a pointer so that we can re-assign it in
1496
+ {I}// the constructors and assignment operations.
1497
+ {I}const std::shared_ptr<types::IClass>* instance_;
1498
+
1499
+ {I}// Iterator over the instances referenced from this instance
1500
+ {I}// in the outer loop
1501
+ {I}std::unique_ptr<impl::IIterator> non_recursive_iterator_;
1502
+
1503
+ {I}// Iterator for recursion into the reference referenced from this instance
1504
+ {I}// in the inner loop
1505
+ {I}std::unique_ptr<impl::IIterator> recursive_iterator_;
1506
+
1507
+ {I}const std::shared_ptr<types::IClass>* item_;
1508
+
1509
+ {I}bool done_;
1510
+ {I}long index_;
1511
+ {I}size_t state_;
1512
+
1513
+ {I}void Execute();
1514
+ }}; // class RecursiveInclusiveIterator"""
1515
+ ),
1516
+ Stripped(
1517
+ f"""\
1518
+ /**
1519
+ * Iterate recursively over the instance, excluding the instance in the iteration.
1520
+ *
1521
+ * This is a realisation of the following pseudo-code:
1522
+ * \\code
1523
+ * stack = new Stack();
1524
+ * stack.push(instance);
1525
+ * while not stack.empty():
1526
+ * some_instance = stack.pop()
1527
+ * if some_instance is not instance:
1528
+ * yield some_instance
1529
+ *
1530
+ * it = new_non_recursive_iterator(some_instance)
1531
+ * while not it.done():
1532
+ * yield recursively from it.get()
1533
+ * it.next()
1534
+ * \\endcode
1535
+ */
1536
+ class RecursiveExclusiveIterator : public impl::IIterator {{
1537
+ public:
1538
+ {I}RecursiveExclusiveIterator(
1539
+ {II}const std::shared_ptr<types::IClass>& instance
1540
+ {I});
1541
+
1542
+ {I}void Start() override;
1543
+ {I}void Next() override;
1544
+ {I}bool Done() const override;
1545
+ {I}const std::shared_ptr<types::IClass>& Get() const override;
1546
+ {I}long Index() const override;
1547
+ {I}void PrependToPath(Path* path) const override;
1548
+ {I}std::unique_ptr<impl::IIterator> Clone() const override;
1549
+ {I}~RecursiveExclusiveIterator() override = default;
1550
+
1551
+ private:
1552
+ {I}RecursiveInclusiveIterator inclusive_iterator_;
1553
+ }}; // class RecursiveExclusiveIterator"""
1554
+ ),
1555
+ Stripped("// region RecursiveInclusiveIterator implementation"),
1556
+ Stripped(
1557
+ f"""\
1558
+ RecursiveInclusiveIterator::RecursiveInclusiveIterator(
1559
+ {I}const std::shared_ptr<types::IClass>& instance
1560
+ ) : instance_(&instance), item_(nullptr), index_(-1) {{
1561
+ {I}// Intentionally empty.
1562
+ }}"""
1563
+ ),
1564
+ Stripped(
1565
+ f"""\
1566
+ RecursiveInclusiveIterator::RecursiveInclusiveIterator(
1567
+ {I}const RecursiveInclusiveIterator& other
1568
+ ) {{
1569
+ {I}instance_ = other.instance_;
1570
+ {I}non_recursive_iterator_ = (other.non_recursive_iterator_ == nullptr)
1571
+ {II}? nullptr
1572
+ {II}: other.non_recursive_iterator_->Clone();
1573
+ {I}recursive_iterator_ = (other.recursive_iterator_ == nullptr)
1574
+ {II}? nullptr
1575
+ {II}: other.recursive_iterator_->Clone();
1576
+ {I}item_ = other.item_;
1577
+ {I}done_ = other.done_;
1578
+ {I}index_ = other.index_;
1579
+ {I}state_ = other.state_;
1580
+ }}"""
1581
+ ),
1582
+ Stripped(
1583
+ f"""\
1584
+ RecursiveInclusiveIterator::RecursiveInclusiveIterator(
1585
+ {I}RecursiveInclusiveIterator&& other
1586
+ ) {{
1587
+ {I}instance_ = other.instance_;
1588
+ {I}non_recursive_iterator_ = std::move(other.non_recursive_iterator_);
1589
+ {I}recursive_iterator_ = std::move(other.recursive_iterator_);
1590
+ {I}item_ = other.item_;
1591
+ {I}done_ = other.done_;
1592
+ {I}index_ = other.index_;
1593
+ {I}state_ = other.state_;
1594
+ }}"""
1595
+ ),
1596
+ Stripped(
1597
+ f"""\
1598
+ RecursiveInclusiveIterator& RecursiveInclusiveIterator::operator=(
1599
+ {I}const RecursiveInclusiveIterator& other
1600
+ ) {{
1601
+ {I}return *this = RecursiveInclusiveIterator(other);
1602
+ }}"""
1603
+ ),
1604
+ Stripped(
1605
+ f"""\
1606
+ RecursiveInclusiveIterator& RecursiveInclusiveIterator::operator=(
1607
+ {I}RecursiveInclusiveIterator&& other
1608
+ ) {{
1609
+ {I}if (this != &other) {{
1610
+ {II}instance_ = other.instance_;
1611
+ {II}non_recursive_iterator_ = std::move(other.non_recursive_iterator_);
1612
+ {II}recursive_iterator_ = std::move(other.recursive_iterator_);
1613
+ {II}item_ = other.item_;
1614
+ {II}done_ = other.done_;
1615
+ {II}index_ = other.index_;
1616
+ {II}state_ = other.state_;
1617
+ {I}}}
1618
+
1619
+ {I}return *this;
1620
+ }}"""
1621
+ ),
1622
+ Stripped(
1623
+ f"""\
1624
+ void RecursiveInclusiveIterator::Start() {{
1625
+ {I}state_ = 0;
1626
+ {I}Execute();
1627
+
1628
+ {I}#ifdef DEBUG
1629
+ {I}if (Done()) {{
1630
+ {II}throw std::logic_error(
1631
+ {III}"Expected RecursiveInclusiveIterator not to be done at start, but it was."
1632
+ {II});
1633
+ {I}}}
1634
+
1635
+ {I}if (Index() !== 0) {{
1636
+ {II}throw std::logic_error(
1637
+ {III}common::Concat(
1638
+ {IIII}"Expected RecursiveInclusiveIterator::Index() to be 0 on Start()"
1639
+ {IIII}", but got ",
1640
+ {IIII}std::to_string(Index())
1641
+ {III})
1642
+ {II});
1643
+ {I}}}
1644
+
1645
+ {I}const std::shared_ptr<IClass>& current_item(Get());
1646
+ {I}if (current_item == nullptr) {{
1647
+ {II}throw std::logic_error(
1648
+ {III}"Unexpected null pointer from Get() at the end of "
1649
+ {III}"RecursiveInclusiveIterator::Start"
1650
+ {II});
1651
+ {I}}}
1652
+
1653
+ {I}if (current_item.get() != instance_.get()) {{
1654
+ {II}throw std::logic_error(
1655
+ {III}common::Concat(
1656
+ {IIII}"Expected the current item to point to the instance "
1657
+ {IIII}"at the end of RecursiveInclusiveIterator::Start, "
1658
+ {IIII}"but got ",
1659
+ {IIII}std::to_string(current_item.get()),
1660
+ {IIII}" from Get() instead of ",
1661
+ {IIII}std::to_string(instance_.get())
1662
+ {III})
1663
+ {II});
1664
+ {I}}}
1665
+ {I}#endif
1666
+ }}"""
1667
+ ),
1668
+ Stripped(
1669
+ f"""\
1670
+ void RecursiveInclusiveIterator::Next() {{
1671
+ {I}#ifdef DEBUG
1672
+ {I}if (Done()) {{
1673
+ {II}throw std::logic_error(
1674
+ {III}"You want to move a RecursiveInclusiveIterator, but it was done."
1675
+ {II});
1676
+ {I}}}
1677
+ {I}#endif
1678
+
1679
+ {I}Execute();
1680
+ }}"""
1681
+ ),
1682
+ Stripped(
1683
+ f"""\
1684
+ bool RecursiveInclusiveIterator::Done() const {{
1685
+ {I}return done_;
1686
+ }}"""
1687
+ ),
1688
+ Stripped(
1689
+ f"""\
1690
+ const std::shared_ptr<types::IClass>& RecursiveInclusiveIterator::Get() const {{
1691
+ {I}#ifdef DEBUG
1692
+ {I}if (Done()) {{
1693
+ {II}throw std::logic_error(
1694
+ {III}"You want to get from RecursiveInclusiveIterator, but it was done."
1695
+ {II});
1696
+ {I}}}
1697
+
1698
+ {I}if (item_ == nullptr) {{
1699
+ {II}throw std::logic_error(
1700
+ {III}"You want to get from a RecursiveInclusiveIterator, "
1701
+ {III}"but item_ has not been set."
1702
+ {II});
1703
+ {I}}}
1704
+ {I}#endif
1705
+
1706
+ {I}return *item_;
1707
+ }}"""
1708
+ ),
1709
+ Stripped(
1710
+ f"""\
1711
+ long RecursiveInclusiveIterator::Index() const {{
1712
+ {I}#ifdef DEBUG
1713
+ {I}if (Done() && index_ != -1) {{
1714
+ {II}throw std::logic_error(
1715
+ {III}common::Concat(
1716
+ {IIII}"Expected index to be -1 on a done RecursiveInclusiveIterator, "
1717
+ {IIII}"but got: ",
1718
+ {IIII}std::to_string(index_)
1719
+ {III})
1720
+ {II});
1721
+ {I}}}
1722
+ {I}#endif
1723
+
1724
+ {I}return index_;
1725
+ }}"""
1726
+ ),
1727
+ Stripped(
1728
+ f"""\
1729
+ void RecursiveInclusiveIterator::PrependToPath(Path* path) const {{
1730
+ {I}#ifdef DEBUG
1731
+ {I}if (Done()) {{
1732
+ {II}throw std::logic_error(
1733
+ {III}"You want to prepend to path from RecursiveInclusiveIterator, "
1734
+ {III}"but the iterator was done."
1735
+ {II});
1736
+ {I}}}
1737
+ {I}#endif
1738
+
1739
+ {I}if (Index() == 0) {{
1740
+ {II}// Index set to 0 indicates that the iterator points to the instance itself.
1741
+ {II}// Therefore, there is nothing to prepend to the path.
1742
+ {II}return;
1743
+ {I}}}
1744
+
1745
+ {I}if (recursive_iterator_ != nullptr) {{
1746
+ {II}recursive_iterator_->PrependToPath(path);
1747
+ {I}}}
1748
+
1749
+ {I}if (non_recursive_iterator_ != nullptr) {{
1750
+ {II}non_recursive_iterator_->PrependToPath(path);
1751
+ {I}}}
1752
+ }}"""
1753
+ ),
1754
+ Stripped(
1755
+ f"""\
1756
+ std::unique_ptr<impl::IIterator> RecursiveInclusiveIterator::Clone() const {{
1757
+ {I}return common::make_unique<RecursiveInclusiveIterator>(*this);
1758
+ }}"""
1759
+ ),
1760
+ execute_block,
1761
+ Stripped("// endregion RecursiveInclusiveIterator implementation"),
1762
+ Stripped("// region RecursiveExclusiveIterator implementation"),
1763
+ Stripped(
1764
+ f"""\
1765
+ RecursiveExclusiveIterator::RecursiveExclusiveIterator(
1766
+ {I}const std::shared_ptr<types::IClass>& instance
1767
+ ) : inclusive_iterator_(instance) {{
1768
+ {I}// Intentionally empty.
1769
+ }}"""
1770
+ ),
1771
+ Stripped(
1772
+ f"""\
1773
+ void RecursiveExclusiveIterator::Start() {{
1774
+ {I}inclusive_iterator_.Start();
1775
+
1776
+ {I}#ifdef DEBUG
1777
+ {I}if (inclusive_iterator_.Done()) {{
1778
+ {II}throw std::logic_error(
1779
+ {III}"Expected the inclusive iterator to be not-done immediately after start, "
1780
+ {III}"as the first item is expected to point to the instance itself, "
1781
+ {III}"but the inclusive iterator was done."
1782
+ {II});
1783
+ {I}}}
1784
+ {I}#endif
1785
+
1786
+ {I}// Simply skip the instance in the very first yield.
1787
+ {I}inclusive_iterator_.Next();
1788
+ }}"""
1789
+ ),
1790
+ Stripped(
1791
+ f"""\
1792
+ void RecursiveExclusiveIterator::Next() {{
1793
+ {I}#ifdef DEBUG
1794
+ {I}if (Done()) {{
1795
+ {II}throw std::logic_error(
1796
+ {III}"You want to move a RecursiveExclusiveIterator, but it was done."
1797
+ {II});
1798
+ {I}}}
1799
+ {I}#endif
1800
+
1801
+ {I}inclusive_iterator_.Next();
1802
+ }}"""
1803
+ ),
1804
+ Stripped(
1805
+ f"""\
1806
+ bool RecursiveExclusiveIterator::Done() const {{
1807
+ {I}return inclusive_iterator_.Done();
1808
+ }}"""
1809
+ ),
1810
+ Stripped(
1811
+ f"""\
1812
+ const std::shared_ptr<types::IClass>& RecursiveExclusiveIterator::Get() const {{
1813
+ {I}#ifdef DEBUG
1814
+ {I}if (Done()) {{
1815
+ {II}throw std::logic_error(
1816
+ {III}"You want to get from RecursiveExclusiveIterator, but it was done."
1817
+ {II});
1818
+ {I}}}
1819
+ {I}#endif
1820
+
1821
+ {I}return inclusive_iterator_.Get();
1822
+ }}"""
1823
+ ),
1824
+ Stripped(
1825
+ f"""\
1826
+ long RecursiveExclusiveIterator::Index() const {{
1827
+ {I}if (inclusive_iterator_.Done()) {{
1828
+ {II}return -1;
1829
+ {I}}}
1830
+
1831
+ {I}return inclusive_iterator_.Index() - 1;
1832
+ }}"""
1833
+ ),
1834
+ Stripped(
1835
+ f"""\
1836
+ void RecursiveExclusiveIterator::PrependToPath(Path* path) const {{
1837
+ {I}inclusive_iterator_.PrependToPath(path);
1838
+ }}"""
1839
+ ),
1840
+ Stripped(
1841
+ f"""\
1842
+ std::unique_ptr<impl::IIterator> RecursiveExclusiveIterator::Clone() const {{
1843
+ {I}return common::make_unique<RecursiveExclusiveIterator>(*this);
1844
+ }}"""
1845
+ ),
1846
+ Stripped("// endregion RecursiveExclusiveIterator implementation"),
1847
+ ]
1848
+
1849
+
1850
+ def _generate_descent_and_descent_once_implementations() -> List[Stripped]:
1851
+ """Generate the implementation of the descent iterables."""
1852
+ new_non_recursive_iterator = cpp_naming.function_name(
1853
+ Identifier("new_non_recursive_iterator")
1854
+ )
1855
+
1856
+ return [
1857
+ Stripped(
1858
+ f"""\
1859
+ // region Descent
1860
+
1861
+ // NOTE (mristin):
1862
+ // We have to make a copy of the pointer since we would lose otherwise
1863
+ // in range-based `for` loops,
1864
+ // see: https://stackoverflow.com/questions/29990045/temporary-lifetime-in-range-for-expression
1865
+ Descent::Descent(
1866
+ {I}std::shared_ptr<types::IClass> instance
1867
+ ) : instance_(std::move(instance)) {{
1868
+ {I}// Intentionally empty.
1869
+ }}
1870
+
1871
+ Iterator Descent::begin() const {{
1872
+ {I}std::unique_ptr<impl::IIterator> it_impl(
1873
+ {II}std::move(
1874
+ {III}common::make_unique<RecursiveExclusiveIterator>(instance_)
1875
+ {II})
1876
+ {I});
1877
+
1878
+ {I}it_impl->Start();
1879
+
1880
+ {I}// NOTE(mristin):
1881
+ {I}// We short-circuit here for memory frugality,
1882
+ {I}// as we can immediately dispose it_impl.
1883
+ {I}if (it_impl->Done()) {{
1884
+ {II}return end();
1885
+ {I}}}
1886
+
1887
+ {I}return Iterator(std::move(it_impl));
1888
+ }}
1889
+
1890
+ const Iterator& Descent::end() const {{
1891
+ {I}static Iterator iterator(common::make_unique<AlwaysDoneIterator>());
1892
+ {I}return iterator;
1893
+ }}
1894
+
1895
+ // endregion Descent"""
1896
+ ),
1897
+ Stripped(
1898
+ f"""\
1899
+ // region DescentOnce
1900
+
1901
+ // NOTE (mristin):
1902
+ // We have to make a copy of the pointer since we would lose otherwise
1903
+ // in range-based `for` loops,
1904
+ // see: https://stackoverflow.com/questions/29990045/temporary-lifetime-in-range-for-expression
1905
+ DescentOnce::DescentOnce(
1906
+ {I}std::shared_ptr<types::IClass> instance
1907
+ ) : instance_(std::move(instance)) {{
1908
+ {I}// Intentionally empty.
1909
+ }}
1910
+
1911
+ Iterator DescentOnce::begin() const {{
1912
+ {I}std::unique_ptr<impl::IIterator> it_impl(
1913
+ {II}{new_non_recursive_iterator}(instance_)
1914
+ {I});
1915
+
1916
+ {I}it_impl->Start();
1917
+
1918
+ {I}// NOTE(mristin):
1919
+ {I}// We short-circuit here for efficiency, as we can immediately dispose it_impl.
1920
+ {I}if (it_impl->Done()) {{
1921
+ {II}return Iterator(std::move(common::make_unique<AlwaysDoneIterator>()));
1922
+ {I}}}
1923
+
1924
+ {I}return Iterator(std::move(it_impl));
1925
+ }}
1926
+
1927
+ const Iterator& DescentOnce::end() const {{
1928
+ {I}static Iterator iterator(common::make_unique<AlwaysDoneIterator>());
1929
+ {I}return iterator;
1930
+ }}
1931
+
1932
+ // endregion DescentOnce"""
1933
+ ),
1934
+ ]
1935
+
1936
+
1937
+ def _generate_constructor_implementation(cls: intermediate.ConcreteClass) -> Stripped:
1938
+ """Transpile the constructor implementation for the given ``cls``."""
1939
+ assert all(
1940
+ isinstance(stmt, intermediate_construction.AssignArgument)
1941
+ for stmt in cls.constructor.inlined_statements
1942
+ ), (
1943
+ f"We expect only assigns in the inlined constructors, "
1944
+ f"but got for class {cls.name!r}: {cls.constructor.inlined_statements}"
1945
+ )
1946
+
1947
+ body_statements = [] # type: List[Stripped]
1948
+
1949
+ for stmt in cls.constructor.inlined_statements:
1950
+ assert isinstance(stmt, intermediate_construction.AssignArgument), (
1951
+ f"Only assigns expected in inlined constructors, but got the following "
1952
+ f"statement for the class {cls.name!r}: {stmt}"
1953
+ )
1954
+
1955
+ prop_member = cpp_naming.private_property_name(stmt.name)
1956
+ arg_name = cpp_naming.argument_name(stmt.argument)
1957
+
1958
+ if stmt.default is not None:
1959
+ if isinstance(stmt.default, intermediate_construction.EmptyList):
1960
+ body_statements.append(
1961
+ Stripped(
1962
+ f"""\
1963
+ if ({arg_name}.has_value()) {{
1964
+ {I}{prop_member} = *{arg_name};
1965
+ }} else {{
1966
+ {I}{prop_member}.emplace();
1967
+ }}"""
1968
+ )
1969
+ )
1970
+ elif isinstance(stmt.default, intermediate_construction.DefaultEnumLiteral):
1971
+ enum_name = cpp_naming.enum_name(stmt.default.enum.name)
1972
+ literal_name = cpp_naming.enum_literal_name(stmt.default.literal.name)
1973
+
1974
+ body_statements.append(
1975
+ Stripped(
1976
+ f"""\
1977
+ {prop_member} = ({arg_name}.has_value())
1978
+ {I}? *{arg_name}
1979
+ {I}: {enum_name}::{literal_name};"""
1980
+ )
1981
+ )
1982
+ else:
1983
+ assert_never(stmt.default)
1984
+
1985
+ else:
1986
+ prop = cls.properties_by_name[stmt.name]
1987
+ if cpp_common.is_referencable(prop.type_annotation):
1988
+ body_statements.append(
1989
+ Stripped(f"{prop_member} = std::move({arg_name});")
1990
+ )
1991
+ else:
1992
+ body_statements.append(Stripped(f"{prop_member} = {arg_name};"))
1993
+
1994
+ body = (
1995
+ "\n\n".join(body_statements)
1996
+ if len(body_statements) > 0
1997
+ else "// Intentionally empty."
1998
+ )
1999
+
2000
+ cls_name = cpp_naming.class_name(cls.name)
2001
+
2002
+ if len(cls.constructor.arguments) == 0:
2003
+ return Stripped(
2004
+ f"""\
2005
+ {cls_name}::{cls_name}() {{
2006
+ {I}{indent_but_first_line(body, I)}
2007
+ }}"""
2008
+ )
2009
+
2010
+ constructor_argument_specs = [] # type: List[str]
2011
+ for arg in cls.constructor.arguments:
2012
+ arg_type = cpp_common.generate_type(arg.type_annotation)
2013
+ arg_name = cpp_naming.argument_name(arg.name)
2014
+
2015
+ constructor_argument_specs.append(f"{arg_type} {arg_name}")
2016
+
2017
+ constructor_arguments_specs_joined = ",\n".join(constructor_argument_specs)
2018
+
2019
+ return Stripped(
2020
+ f"""\
2021
+ {cls_name}::{cls_name}(
2022
+ {I}{indent_but_first_line(constructor_arguments_specs_joined, I)}
2023
+ ) {{
2024
+ {I}{indent_but_first_line(body, I)}
2025
+ }}"""
2026
+ )
2027
+
2028
+
2029
+ def _generate_always_done_iterator() -> Stripped:
2030
+ """Generate the definition and implementation of the end-of-descent iterator."""
2031
+ return Stripped(
2032
+ f"""\
2033
+ /**
2034
+ * This iterator is always done.
2035
+ *
2036
+ * It is used for efficient comparisons against end-of-descent.
2037
+ */
2038
+ class AlwaysDoneIterator : public impl::IIterator {{
2039
+ public:
2040
+ {I}void Start() override {{
2041
+ {II}// Intentionally empty.
2042
+ {I}}}
2043
+
2044
+ {I}void Next() override {{
2045
+ {II}throw std::logic_error(
2046
+ {III}"You want to move an AlwaysDoneIterator, "
2047
+ {III}"but the iterator is always done, as its name suggests."
2048
+ {II});
2049
+ {I}}}
2050
+
2051
+ {I}bool Done() const override {{
2052
+ {II}return true;
2053
+ {I}}}
2054
+
2055
+ {I}const std::shared_ptr<types::IClass>& Get() const override {{
2056
+ {II}throw std::logic_error(
2057
+ {III}"You want to get from an AlwaysDoneIterator, "
2058
+ {III}"but the iterator is always done, as its name suggests."
2059
+ {II});
2060
+ {I}}}
2061
+
2062
+ {I}std::unique_ptr<IIterator> Clone() const override {{
2063
+ {II}return common::make_unique<AlwaysDoneIterator>(*this);
2064
+ {I}}};
2065
+
2066
+ {I}void PrependToPath(Path*) const override {{
2067
+ {II}throw std::logic_error(
2068
+ {III}"You want to prepend to path from an AlwaysDoneIterator, "
2069
+ {III}"but the iterator is always done, as its name suggests."
2070
+ {II});
2071
+ {I}}}
2072
+
2073
+ {I}long Index() const override {{
2074
+ {II}return -1;
2075
+ {I}}}
2076
+
2077
+ {I}~AlwaysDoneIterator() override = default;
2078
+ }}; // class AlwaysDoneIterator"""
2079
+ )
2080
+
2081
+
2082
+ def _generate_iterator_implementation() -> List[Stripped]:
2083
+ """Generate the impl. of the facade ``Iterator`` around ``impl::Iterator``."""
2084
+ return [
2085
+ Stripped(
2086
+ f"""\
2087
+ Iterator::Iterator(
2088
+ {I}const Iterator& other
2089
+ ) : implementation_(other.implementation_->Clone()) {{
2090
+ {I}// Intentionally empty.
2091
+ }}"""
2092
+ ),
2093
+ Stripped(
2094
+ f"""\
2095
+ Iterator::Iterator(
2096
+ {I}Iterator&& other
2097
+ ) : implementation_(std::move(other.implementation_)) {{
2098
+ {I}// Intentionally empty.
2099
+ }}"""
2100
+ ),
2101
+ Stripped(
2102
+ f"""\
2103
+ Iterator& Iterator::operator=(const Iterator& other) {{
2104
+ {I}return *this = Iterator(other);
2105
+ }}"""
2106
+ ),
2107
+ Stripped(
2108
+ f"""\
2109
+ Iterator& Iterator::operator=(Iterator&& other) {{
2110
+ {I}if (this != &other) {{
2111
+ {II}this->implementation_ = std::move(other.implementation_);
2112
+ {I}}}
2113
+
2114
+ {I}return *this;
2115
+ }}"""
2116
+ ),
2117
+ Stripped(
2118
+ f"""\
2119
+ const std::shared_ptr<types::IClass>& Iterator::operator*() const {{
2120
+ {I}if (implementation_->Done()) {{
2121
+ {II}throw std::logic_error(
2122
+ {III}"You want to dereference a completed iterator."
2123
+ {II});
2124
+ {I}}}
2125
+
2126
+ {I}return implementation_->Get();
2127
+ }}"""
2128
+ ),
2129
+ Stripped(
2130
+ f"""\
2131
+ const std::shared_ptr<types::IClass>* Iterator::operator->() {{
2132
+ {I}if (implementation_->Done()) {{
2133
+ {II}throw std::logic_error(
2134
+ {III}"You want to dereference a completed iterator."
2135
+ {II});
2136
+ {I}}}
2137
+
2138
+ {I}return &(implementation_->Get());
2139
+ }}"""
2140
+ ),
2141
+ Stripped(
2142
+ f"""\
2143
+ // Prefix increment
2144
+ Iterator& Iterator::operator++() {{
2145
+ {I}if (implementation_->Done()) {{
2146
+ {II}throw std::logic_error(
2147
+ {III}"You want to move a completed iterator."
2148
+ {II});
2149
+ {I}}}
2150
+
2151
+ {I}implementation_->Next();
2152
+ {I}return *this;
2153
+ }}"""
2154
+ ),
2155
+ Stripped(
2156
+ f"""\
2157
+ // Postfix increment
2158
+ Iterator Iterator::operator++(int) {{
2159
+ {I}Iterator result(*this);
2160
+ {I}++(*this);
2161
+ {I}return result;
2162
+ }}"""
2163
+ ),
2164
+ Stripped(
2165
+ f"""\
2166
+ bool operator==(const Iterator& a, const Iterator& b) {{
2167
+ {I}return a.implementation_->Index() == b.implementation_->Index();
2168
+ }}"""
2169
+ ),
2170
+ Stripped(
2171
+ f"""\
2172
+ bool operator!=(const Iterator& a, const Iterator& b) {{
2173
+ {I}return a.implementation_->Index() != b.implementation_->Index();
2174
+ }}"""
2175
+ ),
2176
+ Stripped(
2177
+ f"""\
2178
+ Path MaterializePath(const Iterator& iterator) {{
2179
+ {I}if (iterator.implementation_->Done()) {{
2180
+ {II}throw std::logic_error(
2181
+ {III}"You want to materialize path of a completed iterator."
2182
+ {II});
2183
+ {I}}}
2184
+
2185
+ {I}Path path;
2186
+ {I}iterator.implementation_->PrependToPath(&path);
2187
+ {I}return path;
2188
+ }}"""
2189
+ ),
2190
+ Stripped(
2191
+ f"""\
2192
+ void PrependToPath(const Iterator& iterator, Path* path) {{
2193
+ {I}if (iterator.implementation_->Done()) {{
2194
+ {II}throw std::logic_error(
2195
+ {III}"You want to prepend a path of a completed iterator."
2196
+ {II});
2197
+ {I}}}
2198
+
2199
+ {I}iterator.implementation_->PrependToPath(path);
2200
+ }}"""
2201
+ ),
2202
+ ]
2203
+
2204
+
2205
+ def _generate_over_enum_implementation(enum: intermediate.Enumeration) -> Stripped:
2206
+ """Generate the implementation for a container over ``enum`` literals."""
2207
+ enum_name = cpp_naming.enum_name(enum.name)
2208
+ over_enum = cpp_naming.constant_name(Identifier(f"over_{enum.name}"))
2209
+
2210
+ literals = [] # type: List[Stripped]
2211
+ for literal in enum.literals:
2212
+ literal_name = cpp_naming.enum_literal_name(literal.name)
2213
+ literals.append(Stripped(f"types::{enum_name}::{literal_name}"))
2214
+
2215
+ literals_joined = ",\n".join(literals)
2216
+
2217
+ return Stripped(
2218
+ f"""\
2219
+ const std::vector<types::{enum_name}> {over_enum} = {{
2220
+ {I}{indent_but_first_line(literals_joined, I)}
2221
+ }};"""
2222
+ )
2223
+
2224
+
2225
+ # fmt: off
2226
+ @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
2227
+ @ensure(
2228
+ lambda result:
2229
+ not (result[0] is not None) or result[0].endswith('\n'),
2230
+ "Trailing newline mandatory for valid end-of-files"
2231
+ )
2232
+ # fmt: on
2233
+ def generate_implementation(
2234
+ symbol_table: intermediate.SymbolTable, library_namespace: Stripped
2235
+ ) -> Tuple[Optional[str], Optional[List[Error]]]:
2236
+ """Generate the C++ implementation of the iteration functions and structures."""
2237
+ namespace = Stripped(f"{library_namespace}::iteration")
2238
+
2239
+ include_prefix_path = cpp_common.generate_include_prefix_path(library_namespace)
2240
+
2241
+ blocks = [
2242
+ cpp_common.WARNING,
2243
+ Stripped(
2244
+ f'''\
2245
+ #include "{include_prefix_path}/common.hpp"
2246
+ #include "{include_prefix_path}/iteration.hpp"'''
2247
+ ),
2248
+ cpp_common.generate_namespace_opening(namespace),
2249
+ Stripped("// region Pathing"),
2250
+ _generate_property_to_wstring_implementation(symbol_table=symbol_table),
2251
+ *_generate_property_segment_implementation(),
2252
+ *_generate_index_segment_implementation(),
2253
+ *_generate_path_implementation(),
2254
+ Stripped("// endregion Pathing"),
2255
+ Stripped("// region Non-recursive iteration"),
2256
+ ] # type: List[Stripped]
2257
+
2258
+ errors = [] # type: List[Error]
2259
+
2260
+ for cls in symbol_table.concrete_classes:
2261
+ if cls.is_implementation_specific:
2262
+ errors.append(
2263
+ Error(
2264
+ cls.parsed.node,
2265
+ f"NOTE (mristin, 2023-09-27): "
2266
+ f"The class {cls.name!r} is marked as implementation specific. "
2267
+ f"However, we currently do not generate the C++ iteration code "
2268
+ f"over implementation-specific classes. Please contact "
2269
+ f"the developers if you need this feature.",
2270
+ )
2271
+ )
2272
+ continue
2273
+
2274
+ blocks.extend(_generate_iteration_over_cls(cls=cls))
2275
+
2276
+ blocks.append(_generate_always_done_iterator())
2277
+
2278
+ blocks.append(
2279
+ _generate_new_non_recursive_iterator_function(symbol_table=symbol_table)
2280
+ )
2281
+
2282
+ blocks.append(Stripped("// endregion Non-recursive iteration"))
2283
+
2284
+ blocks.append(Stripped("// region Recursive iteration"))
2285
+
2286
+ blocks.extend(_generate_recursive_iteration())
2287
+
2288
+ blocks.append(Stripped("// endregion Recursive iteration"))
2289
+
2290
+ blocks.append(Stripped("// region Iterator facade"))
2291
+
2292
+ blocks.extend(_generate_iterator_implementation())
2293
+
2294
+ blocks.append(Stripped("// endregion Iterator facade"))
2295
+
2296
+ blocks.append(Stripped("// region Descents"))
2297
+
2298
+ blocks.extend(_generate_descent_and_descent_once_implementations())
2299
+
2300
+ blocks.append(Stripped("// endregion Descents"))
2301
+
2302
+ if len(symbol_table.enumerations) > 0:
2303
+ blocks.append(Stripped("// region Over enumerations"))
2304
+
2305
+ for enum in symbol_table.enumerations:
2306
+ blocks.append(_generate_over_enum_implementation(enum))
2307
+
2308
+ blocks.append(Stripped("// endregion Over enumerations"))
2309
+
2310
+ if len(errors) > 0:
2311
+ return None, errors
2312
+
2313
+ blocks.extend(
2314
+ [
2315
+ cpp_common.generate_namespace_closing(namespace),
2316
+ cpp_common.WARNING,
2317
+ ]
2318
+ )
2319
+
2320
+ writer = io.StringIO()
2321
+ for i, block in enumerate(blocks):
2322
+ if i > 0:
2323
+ writer.write("\n\n")
2324
+
2325
+ writer.write(block)
2326
+
2327
+ writer.write("\n")
2328
+
2329
+ return writer.getvalue(), None
2330
+
2331
+
2332
+ # endregion