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