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,3940 @@
1
+ """Translate the abstract syntax tree of the meta-model into parsed structures."""
2
+ import ast
3
+ import collections
4
+ import enum
5
+ import io
6
+ import itertools
7
+ import sys
8
+ import textwrap
9
+ from typing import (
10
+ List,
11
+ Any,
12
+ Optional,
13
+ Type,
14
+ Tuple,
15
+ Union,
16
+ Mapping,
17
+ MutableMapping,
18
+ Dict,
19
+ Set,
20
+ Iterable,
21
+ )
22
+
23
+ import asttokens
24
+ import docutils.core
25
+ import docutils.io
26
+ import docutils.nodes
27
+
28
+ from icontract import ensure, require
29
+
30
+ from aas_core_codegen.common import (
31
+ Error,
32
+ Identifier,
33
+ IDENTIFIER_RE,
34
+ LinenoColumner,
35
+ assert_never,
36
+ is_stripped,
37
+ Stripped,
38
+ )
39
+ from aas_core_codegen.parse import tree, _rules
40
+ from aas_core_codegen.parse._types import (
41
+ AbstractClass,
42
+ Argument,
43
+ AtomicTypeAnnotation,
44
+ ConcreteClass,
45
+ Invariant,
46
+ Contract,
47
+ Contracts,
48
+ Default,
49
+ Class,
50
+ Enumeration,
51
+ EnumerationLiteral,
52
+ is_string_expr,
53
+ Serialization,
54
+ Property,
55
+ SelfTypeAnnotation,
56
+ Snapshot,
57
+ SubscriptedTypeAnnotation,
58
+ OurType,
59
+ SymbolTable,
60
+ TypeAnnotation,
61
+ UnverifiedSymbolTable,
62
+ PRIMITIVE_TYPES,
63
+ GENERIC_TYPES,
64
+ Description,
65
+ MetaModel,
66
+ ImplementationSpecificMethod,
67
+ UnderstoodMethod,
68
+ ConstructorToBeUnderstood,
69
+ FunctionUnion,
70
+ MethodUnion,
71
+ ConstantSet,
72
+ Constant,
73
+ ConstantPrimitive,
74
+ ConstantUnion,
75
+ SetLiteral,
76
+ )
77
+
78
+
79
+ # noinspection GrazieInspection
80
+ @ensure(lambda result: (result[0] is None) ^ (result[1] is None))
81
+ def source_to_atok(
82
+ source: str,
83
+ ) -> Tuple[Optional[asttokens.ASTTokens], Optional[Exception]]:
84
+ """
85
+ Parse the Python code.
86
+
87
+ :param source: Python code as text
88
+ :return: parsed module or error, if any
89
+ """
90
+ try:
91
+ atok = asttokens.ASTTokens(source, parse=True)
92
+ except Exception as error:
93
+ return None, error
94
+
95
+ return atok, None
96
+
97
+
98
+ class _ExpectedImportsVisitor(ast.NodeVisitor):
99
+ _EXPECTED_NAME_FROM_MODULE = collections.OrderedDict(
100
+ [
101
+ ("match", "re"),
102
+ ("Enum", "enum"),
103
+ ("List", "typing"),
104
+ ("Optional", "typing"),
105
+ ("Set", "typing"),
106
+ ("DBC", "icontract"),
107
+ ("invariant", "icontract"),
108
+ ("ensure", "icontract"),
109
+ ("require", "icontract"),
110
+ ("abstract", "aas_core_meta.marker"),
111
+ ("constant_set", "aas_core_meta.marker"),
112
+ ("implementation_specific", "aas_core_meta.marker"),
113
+ ("serialization", "aas_core_meta.marker"),
114
+ ("verification", "aas_core_meta.marker"),
115
+ ("non_mutating", "aas_core_meta.marker"),
116
+ ]
117
+ )
118
+
119
+ # pylint: disable=missing-docstring
120
+
121
+ def __init__(self) -> None:
122
+ self.errors = [] # type: List[Error]
123
+
124
+ def visit_Import(self, node: ast.Import) -> Any:
125
+ self.errors.append(
126
+ Error(
127
+ node,
128
+ "Unexpected ``import ...``. "
129
+ "Only ``from ... import...`` statements are expected.",
130
+ )
131
+ )
132
+
133
+ # noinspection PyTypeChecker
134
+ def visit_ImportFrom(self, node: ast.ImportFrom) -> Any:
135
+ for name in node.names:
136
+ assert isinstance(name, ast.alias)
137
+ if name.asname is not None:
138
+ self.errors.append(
139
+ Error(
140
+ name,
141
+ "Unexpected ``from ... import ... as ...``. "
142
+ "Only ``from ... import...`` statements are expected.",
143
+ )
144
+ )
145
+ else:
146
+ if name.name not in self._EXPECTED_NAME_FROM_MODULE:
147
+ self.errors.append(
148
+ Error(name, f"Unexpected import of a name {name.name!r}.")
149
+ )
150
+
151
+ else:
152
+ expected_module = self._EXPECTED_NAME_FROM_MODULE[name.name]
153
+ if expected_module != node.module:
154
+ self.errors.append(
155
+ Error(
156
+ name,
157
+ f"Expected to import {name.name!r} "
158
+ f"from the module {expected_module}, "
159
+ f"but it is imported from {node.module}.",
160
+ )
161
+ )
162
+
163
+
164
+ def check_expected_imports(atok: asttokens.ASTTokens) -> List[str]:
165
+ """
166
+ Check that only expected imports are stated in the module.
167
+
168
+ This is important so that we can parse type annotations and inheritances.
169
+
170
+ Return errors, if any.
171
+ """
172
+ visitor = _ExpectedImportsVisitor()
173
+ assert atok.tree is not None
174
+ visitor.visit(atok.tree)
175
+
176
+ if len(visitor.errors) == 0:
177
+ return []
178
+
179
+ lineno_columner = LinenoColumner(atok=atok)
180
+ return [lineno_columner.error_message(error) for error in visitor.errors]
181
+
182
+
183
+ # noinspection PyTypeChecker
184
+ @ensure(lambda result: (result[0] is None) ^ (result[1] is None))
185
+ def _type_annotation(
186
+ node: ast.AST, atok: asttokens.ASTTokens
187
+ ) -> Tuple[Optional[TypeAnnotation], Optional[Error]]:
188
+ """Parse the type annotation."""
189
+ if isinstance(node, ast.Name):
190
+ return AtomicTypeAnnotation(identifier=Identifier(node.id), node=node), None
191
+
192
+ elif isinstance(node, ast.Constant):
193
+ if not isinstance(node.value, str):
194
+ return (
195
+ None,
196
+ Error(
197
+ node.value,
198
+ f"Expected a string literal "
199
+ f"if the type annotation is given as a constant, "
200
+ f"but got: "
201
+ f"{node.value!r} (as {type(node.value)})",
202
+ ),
203
+ )
204
+
205
+ return AtomicTypeAnnotation(identifier=Identifier(node.value), node=node), None
206
+
207
+ elif isinstance(node, ast.Subscript):
208
+ if not isinstance(node.value, ast.Name):
209
+ return (
210
+ None,
211
+ Error(
212
+ node.value,
213
+ f"Expected a name to define "
214
+ f"a subscripted type annotation,"
215
+ f"but got: {atok.get_text(node.value)}",
216
+ ),
217
+ )
218
+
219
+ # NOTE (mristin, 2022-01-22):
220
+ # There were breaking changes between Python 3.8 and 3.9 in ``ast`` module.
221
+ # Relevant to this particular piece of parsing logic is the deprecation of
222
+ # ``ast.Index`` and ``ast.ExtSlice`` which is replaced with their actual value
223
+ # and ``ast.Tuple``, respectively.
224
+ #
225
+ # Hence, we need to switch on Python version and get the underlying slice value
226
+ # explicitly.
227
+ #
228
+ # See deprecation notes just at the end of:
229
+ # https://docs.python.org/3/library/ast.html#ast.AST
230
+
231
+ if isinstance(node.slice, ast.Slice):
232
+ return (
233
+ None,
234
+ Error(
235
+ node.slice,
236
+ f"Expected an index to define a subscripted type annotation, "
237
+ f"but got a slice: {atok.get_text(node.slice)}",
238
+ ),
239
+ )
240
+
241
+ # noinspection PyUnresolvedReferences
242
+ if (sys.version_info < (3, 9) and isinstance(node.slice, ast.ExtSlice)) or (
243
+ sys.version_info >= (3, 9)
244
+ and isinstance(node.slice, ast.Tuple)
245
+ and any(isinstance(elt, ast.Slice) for elt in node.slice.elts)
246
+ ):
247
+ return (
248
+ None,
249
+ Error(
250
+ node.slice,
251
+ f"Expected an index to define a subscripted type annotation, "
252
+ f"but got an extended slice: {atok.get_text(node.slice)}",
253
+ ),
254
+ )
255
+
256
+ # NOTE (mristin, 2022-01-22):
257
+ # Please see the note about the deprecation of ``ast.Index`` above.
258
+ index_node: ast.AST
259
+ if sys.version_info < (3, 9):
260
+ # noinspection PyUnresolvedReferences
261
+ if isinstance(node.slice, ast.Index):
262
+ index_node = node.slice.value
263
+ else:
264
+ return (
265
+ None,
266
+ Error(
267
+ node.slice,
268
+ f"Expected an index to define a subscripted type annotation, "
269
+ f"but got: {atok.get_text(node.slice)}",
270
+ ),
271
+ )
272
+ else:
273
+ index_node = node.slice
274
+
275
+ subscripts = [] # type: List[TypeAnnotation]
276
+
277
+ if isinstance(index_node, ast.Tuple):
278
+ for elt in index_node.elts:
279
+ subscript_annotation, error = _type_annotation(node=elt, atok=atok)
280
+ if error is not None:
281
+ return None, error
282
+
283
+ assert subscript_annotation is not None
284
+
285
+ subscripts.append(subscript_annotation)
286
+
287
+ elif isinstance(index_node, (ast.Name, ast.Subscript, ast.Constant)):
288
+ subscript_annotation, error = _type_annotation(node=index_node, atok=atok)
289
+ if error is not None:
290
+ return None, error
291
+
292
+ assert subscript_annotation is not None
293
+
294
+ subscripts.append(subscript_annotation)
295
+
296
+ else:
297
+ return (
298
+ None,
299
+ Error(
300
+ index_node,
301
+ f"Expected a tuple, a name, a subscript or a string literal "
302
+ f"for a subscripted type annotation, "
303
+ f"but got: {atok.get_text(index_node)}",
304
+ ),
305
+ )
306
+
307
+ return (
308
+ SubscriptedTypeAnnotation(
309
+ identifier=Identifier(node.value.id),
310
+ subscripts=subscripts,
311
+ node=node,
312
+ ),
313
+ None,
314
+ )
315
+
316
+ else:
317
+ return (
318
+ None,
319
+ Error(
320
+ node,
321
+ f"Expected either atomic type annotation (as name or string literal) "
322
+ f"or a subscripted one (as a subscript), "
323
+ f"but got: {atok.get_text(node)} (as {type(node)})",
324
+ ),
325
+ )
326
+
327
+
328
+ _PRIMITIVE_TYPE_NAMES_TO_CONSTANT_FUNCTION_NAMES: Dict[Identifier, Identifier] = {
329
+ Identifier("bool"): Identifier("constant_bool"),
330
+ Identifier("int"): Identifier("constant_int"),
331
+ Identifier("float"): Identifier("constant_float"),
332
+ Identifier("str"): Identifier("constant_str"),
333
+ Identifier("bytearray"): Identifier("constant_bytearray"),
334
+ }
335
+ # fmt: off
336
+ assert all(
337
+ primitive_type in _PRIMITIVE_TYPE_NAMES_TO_CONSTANT_FUNCTION_NAMES
338
+ for primitive_type in PRIMITIVE_TYPES
339
+ )
340
+ # fmt: on
341
+
342
+ # fmt: off
343
+ _PRIMITIVE_TYPE_NAMES_TO_PYTHON_TYPES: Mapping[
344
+ Identifier,
345
+ Union[Type[bool], Type[int], Type[float], Type[str], Type[bytearray]]
346
+ ] = {
347
+ Identifier("bool"): bool,
348
+ Identifier("int"): int,
349
+ Identifier("float"): float,
350
+ Identifier("str"): str,
351
+ Identifier("bytearray"): bytearray,
352
+ }
353
+ assert all(
354
+ primitive_type in _PRIMITIVE_TYPE_NAMES_TO_PYTHON_TYPES
355
+ for primitive_type in PRIMITIVE_TYPES
356
+ )
357
+
358
+
359
+ @require(lambda constant: isinstance(constant.value, str))
360
+ @ensure(lambda result: (result[0] is None) ^ (result[1] is None))
361
+ def _ast_constant_string_to_description(
362
+ constant: ast.Constant,
363
+ ) -> Tuple[Optional[Description], Optional[Error]]:
364
+ """Extract the docstring from the given string constant."""
365
+ text = constant.value
366
+ assert isinstance(
367
+ text, str
368
+ ), f"Expected a string constant node, but got: {ast.dump(constant)!r}"
369
+
370
+ dedented = textwrap.dedent(text)
371
+
372
+ warnings = io.StringIO()
373
+
374
+ document: docutils.nodes.document
375
+ try:
376
+ document = docutils.core.publish_doctree(
377
+ dedented, settings_overrides={"warning_stream": warnings}
378
+ )
379
+ except Exception as err:
380
+ return None, Error(
381
+ constant, f"Failed to parse the description with docutils: {err}"
382
+ )
383
+
384
+ warnings_text = warnings.getvalue()
385
+ if warnings_text:
386
+ return None, Error(
387
+ constant,
388
+ f"Failed to parse the description with docutils:\n"
389
+ f"{warnings_text.strip()}\n\n"
390
+ f"The original text was: {dedented!r}",
391
+ )
392
+
393
+ assert document is not None
394
+
395
+ return Description(document=document, node=constant), None
396
+ # fmt: on
397
+
398
+
399
+ # noinspection PyTypeChecker
400
+ # fmt: off
401
+ @require(
402
+ lambda primitive_type: primitive_type in PRIMITIVE_TYPES,
403
+ "Expected the type annotation as primitive type"
404
+ )
405
+ @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
406
+ # fmt: on
407
+ def _parse_constant_primitive(
408
+ name: Identifier,
409
+ primitive_type: Identifier,
410
+ node: ast.AnnAssign,
411
+ atok: asttokens.ASTTokens,
412
+ ) -> Tuple[Optional[ConstantPrimitive], Optional[Error]]:
413
+ """Parse the definition of a constant as a call to ``constant_primitive`` marker."""
414
+ expected_func_name = _PRIMITIVE_TYPE_NAMES_TO_CONSTANT_FUNCTION_NAMES[
415
+ primitive_type
416
+ ]
417
+
418
+ if (
419
+ not isinstance(node.value, ast.Call)
420
+ or not isinstance(node.value.func, ast.Name)
421
+ or node.value.func.id != expected_func_name
422
+ ):
423
+ return (
424
+ None,
425
+ Error(
426
+ node.value,
427
+ f"Expected the value of the constant definition {name!r} "
428
+ f"of type {primitive_type} to be "
429
+ f"a call to the function {expected_func_name}, "
430
+ f"but got: {atok.get_text(node.value)}",
431
+ ),
432
+ )
433
+
434
+ value_arg_node = None # type: Optional[ast.expr]
435
+ description_arg_node = None # type: Optional[ast.expr]
436
+
437
+ if len(node.value.args) > 0:
438
+ value_arg_node = node.value.args[0]
439
+
440
+ if len(node.value.args) > 1:
441
+ description_arg_node = node.value.args[1]
442
+
443
+ if len(node.value.args) > 3:
444
+ return None, Error(
445
+ node.value.args[3],
446
+ f"Expected only 3 arguments to {expected_func_name}, "
447
+ f"but got {len(node.value.args)}: {atok.get_text(node.value)}",
448
+ )
449
+
450
+ for kwarg in node.value.keywords:
451
+ if kwarg.arg == "value":
452
+ value_arg_node = kwarg.value
453
+ elif kwarg.arg == "description":
454
+ description_arg_node = kwarg.value
455
+ else:
456
+ return None, Error(
457
+ kwarg,
458
+ f"Unexpected keyword argument "
459
+ f"to {expected_func_name}: {atok.get_text(kwarg)}",
460
+ )
461
+
462
+ # region Parse ``value``
463
+
464
+ if not isinstance(value_arg_node, ast.Constant):
465
+ return (
466
+ None,
467
+ Error(
468
+ value_arg_node,
469
+ f"Expected a literal value, but got: {atok.get_text(value_arg_node)}",
470
+ ),
471
+ )
472
+
473
+ if value_arg_node.value is None:
474
+ return (
475
+ None,
476
+ Error(
477
+ value_arg_node,
478
+ "We do not handle None as a constant at this moment. "
479
+ "Please contact the developers if you need this feature",
480
+ ),
481
+ )
482
+
483
+ expected_type = _PRIMITIVE_TYPE_NAMES_TO_PYTHON_TYPES[primitive_type]
484
+ # noinspection PyTypeHints
485
+ if not isinstance(value_arg_node.value, expected_type):
486
+ return None, Error(
487
+ value_arg_node,
488
+ f"Expected the value as {expected_type}, "
489
+ f"but got {type(value_arg_node.value)}",
490
+ )
491
+
492
+ # endregion
493
+
494
+ # region Parse ``description``
495
+
496
+ description = None # type: Optional[Description]
497
+ if description_arg_node is not None:
498
+ if not isinstance(description_arg_node, ast.Constant) or not isinstance(
499
+ description_arg_node.value, str
500
+ ):
501
+ return None, Error(
502
+ description_arg_node,
503
+ f"Expected string literal as the ``description`` argument, "
504
+ f"but got: {atok.get_text(description_arg_node)}",
505
+ )
506
+
507
+ description, error = _ast_constant_string_to_description(
508
+ constant=description_arg_node
509
+ )
510
+
511
+ if error is not None:
512
+ return None, Error(
513
+ node.value, "Failed to parse the ``description`` argument", [error]
514
+ )
515
+
516
+ assert description is not None
517
+
518
+ # endregion
519
+
520
+ return (
521
+ ConstantPrimitive(
522
+ name=name,
523
+ value=value_arg_node.value,
524
+ description=description,
525
+ node=node,
526
+ ),
527
+ None,
528
+ )
529
+
530
+
531
+ # noinspection PyTypeChecker
532
+ @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
533
+ def _parse_constant_set(
534
+ name: Identifier,
535
+ items_type_annotation: AtomicTypeAnnotation,
536
+ node: ast.AnnAssign,
537
+ atok: asttokens.ASTTokens,
538
+ ) -> Tuple[Optional[ConstantSet], Optional[Error]]:
539
+ expected_func_name = "constant_set"
540
+
541
+ if (
542
+ not isinstance(node.value, ast.Call)
543
+ or not isinstance(node.value.func, ast.Name)
544
+ or node.value.func.id != expected_func_name
545
+ ):
546
+ return (
547
+ None,
548
+ Error(
549
+ node.value,
550
+ f"Expected the value of the constant set definition {name!r} "
551
+ f"to be a call to the function {expected_func_name}, "
552
+ f"but got: {atok.get_text(node.value)}",
553
+ ),
554
+ )
555
+
556
+ # region Determine arguments
557
+
558
+ values_arg_node = None # type: Optional[ast.expr]
559
+ description_arg_node = None # type: Optional[ast.expr]
560
+ superset_of_arg_node = None # type: Optional[ast.expr]
561
+
562
+ if len(node.value.args) > 0:
563
+ values_arg_node = node.value.args[0]
564
+
565
+ if len(node.value.args) > 1:
566
+ description_arg_node = node.value.args[1]
567
+
568
+ if len(node.value.args) > 2:
569
+ superset_of_arg_node = node.value.args[3]
570
+
571
+ if len(node.value.args) > 3:
572
+ return None, Error(
573
+ node.value.args[4],
574
+ f"Expected only 4 arguments to {expected_func_name}, "
575
+ f"but got {len(node.value.args)}: {atok.get_text(node.value)}",
576
+ )
577
+
578
+ for kwarg in node.value.keywords:
579
+ if kwarg.arg == "values":
580
+ values_arg_node = kwarg.value
581
+ elif kwarg.arg == "description":
582
+ description_arg_node = kwarg.value
583
+ elif kwarg.arg == "superset_of":
584
+ superset_of_arg_node = kwarg.value
585
+ else:
586
+ return None, Error(
587
+ kwarg,
588
+ f"Unexpected keyword argument "
589
+ f"to {expected_func_name}: {atok.get_text(kwarg)}",
590
+ )
591
+
592
+ # endregion
593
+
594
+ # region Parse ``values``
595
+
596
+ if values_arg_node is None:
597
+ return None, Error(node.value, "Missing values argument")
598
+
599
+ if not isinstance(values_arg_node, ast.List):
600
+ return None, Error(
601
+ values_arg_node,
602
+ f"Expected the values of a constant set to be a list literal, "
603
+ f"but got: {atok.get_text(values_arg_node)}; "
604
+ f"in AST: {ast.dump(values_arg_node)}",
605
+ )
606
+
607
+ set_literals = [] # type: List[SetLiteral]
608
+ for i, elt in enumerate(values_arg_node.elts):
609
+ if not isinstance(elt, (ast.Attribute, ast.Constant)):
610
+ return None, Error(
611
+ elt,
612
+ f"Expected the values of a constant set to be all literals "
613
+ f"(either an enumeration literal or a literal of a primitive type "
614
+ f"such as str or int), but got at the index {i}: "
615
+ f"{atok.get_text(elt)}; in AST: {ast.dump(elt)}",
616
+ )
617
+
618
+ set_literals.append(SetLiteral(node=elt))
619
+
620
+ # endregion
621
+
622
+ # region Parse ``description``
623
+
624
+ description = None # type: Optional[Description]
625
+
626
+ if description_arg_node is not None:
627
+ if not isinstance(description_arg_node, ast.Constant) or not isinstance(
628
+ description_arg_node.value, str
629
+ ):
630
+ return None, Error(
631
+ description_arg_node,
632
+ f"Expected string literal as the ``description`` argument, "
633
+ f"but got: {atok.get_text(description_arg_node)}; "
634
+ f"in AST: {ast.dump(description_arg_node)}",
635
+ )
636
+
637
+ description, error = _ast_constant_string_to_description(
638
+ constant=description_arg_node
639
+ )
640
+
641
+ if error is not None:
642
+ return None, Error(
643
+ node.value, "Failed to parse the ``description`` argument", [error]
644
+ )
645
+
646
+ assert description is not None
647
+
648
+ # endregion
649
+
650
+ # region Parse ``superset_of``
651
+
652
+ subsets = [] # type: List[Identifier]
653
+
654
+ if superset_of_arg_node is not None:
655
+ if not isinstance(superset_of_arg_node, ast.List):
656
+ return None, Error(
657
+ superset_of_arg_node,
658
+ f"Expected the ``superset_of`` of a constant set to be a list literal, "
659
+ f"but got: {atok.get_text(superset_of_arg_node)}; "
660
+ f"in AST: {ast.dump(superset_of_arg_node)}",
661
+ )
662
+
663
+ for i, elt in enumerate(superset_of_arg_node.elts):
664
+ if not isinstance(elt, ast.Name) or not IDENTIFIER_RE.fullmatch(elt.id):
665
+ return None, Error(
666
+ elt,
667
+ f"Expected the elements of the ``superset_of`` of a constant set "
668
+ f"to be a list of variables (referring to the other sets), "
669
+ f"but got at index {i}: "
670
+ f"{atok.get_text(elt)}; in AST: {ast.dump(elt)}",
671
+ )
672
+
673
+ subsets.append(Identifier(elt.id))
674
+
675
+ # endregion
676
+
677
+ return (
678
+ ConstantSet(
679
+ name=name,
680
+ items_type_annotation=items_type_annotation,
681
+ set_literals=set_literals,
682
+ subsets=subsets,
683
+ description=description,
684
+ node=node,
685
+ ),
686
+ None,
687
+ )
688
+
689
+
690
+ # noinspection PyTypeChecker
691
+ @ensure(lambda result: (result[0] is None) ^ (result[1] is None))
692
+ def _ann_assign_to_constant(
693
+ node: ast.AnnAssign, atok: asttokens.ASTTokens
694
+ ) -> Tuple[Optional[ConstantUnion], Optional[Error]]:
695
+ if not isinstance(node.target, ast.Name):
696
+ return (
697
+ None,
698
+ Error(
699
+ node.target,
700
+ f"Expected target of a constant to be a name, "
701
+ f"but got: {atok.get_text(node.target)}",
702
+ ),
703
+ )
704
+
705
+ if not node.simple:
706
+ return (
707
+ None,
708
+ Error(
709
+ node.target,
710
+ "Expected a constant definition with a simple target (no parentheses!)",
711
+ ),
712
+ )
713
+
714
+ if node.annotation is None:
715
+ return (
716
+ None,
717
+ Error(node.target, "Expected the constant to be annotated with a type"),
718
+ )
719
+
720
+ if node.value is None:
721
+ return (
722
+ None,
723
+ Error(node.value, "Unexpected constant definition without a value"),
724
+ )
725
+
726
+ type_annotation, error = _type_annotation(node=node.annotation, atok=atok)
727
+ if error is not None:
728
+ return None, error
729
+
730
+ assert type_annotation is not None
731
+
732
+ if isinstance(type_annotation, AtomicTypeAnnotation):
733
+ if type_annotation.identifier not in PRIMITIVE_TYPES:
734
+ return (
735
+ None,
736
+ Error(
737
+ node.annotation,
738
+ "We only handle definition of constant sets and primitive values "
739
+ f"at the moment, but you defined a constant "
740
+ f"of type {type_annotation.identifier!r}. "
741
+ f"Please contact the developers if you really need this feature",
742
+ ),
743
+ )
744
+
745
+ return _parse_constant_primitive(
746
+ name=Identifier(node.target.id),
747
+ primitive_type=type_annotation.identifier,
748
+ node=node,
749
+ atok=atok,
750
+ )
751
+ elif isinstance(type_annotation, SubscriptedTypeAnnotation):
752
+ if type_annotation.identifier == "Set":
753
+ if len(type_annotation.subscripts) != 1:
754
+ return (
755
+ None,
756
+ Error(
757
+ node.annotation,
758
+ f"Expected exactly one subscript in the type annotation "
759
+ f"of the constant set {node.target.id!r}, "
760
+ f"but got {len(type_annotation.subscripts)}: "
761
+ f"{atok.get_text(node.annotation)}",
762
+ ),
763
+ )
764
+
765
+ items_type_annotation = type_annotation.subscripts[0]
766
+ if not isinstance(items_type_annotation, AtomicTypeAnnotation):
767
+ return (
768
+ None,
769
+ Error(
770
+ node.annotation,
771
+ f"We only support constant sets of atomic types at the moment, "
772
+ f"but we got a subscripted type "
773
+ f"for the items: {atok.get_text(items_type_annotation)}. "
774
+ f"Please contact the developers if you need this feature",
775
+ ),
776
+ )
777
+
778
+ return _parse_constant_set(
779
+ name=Identifier(node.target.id),
780
+ items_type_annotation=items_type_annotation,
781
+ node=node,
782
+ atok=atok,
783
+ )
784
+ else:
785
+ return (
786
+ None,
787
+ Error(
788
+ node.annotation,
789
+ f"We do not know how to handle "
790
+ f"the type annotation: {type_annotation.identifier!r}",
791
+ ),
792
+ )
793
+
794
+ elif isinstance(type_annotation, SelfTypeAnnotation):
795
+ raise AssertionError(
796
+ f"Unexpected {SelfTypeAnnotation.__name__} in the constant definition. "
797
+ f"This is a bug as {SelfTypeAnnotation.__name__} are generated by our "
798
+ f"code, but can not be supplied through user input"
799
+ )
800
+ else:
801
+ assert_never(type_annotation)
802
+
803
+
804
+ # noinspection PyTypeChecker
805
+ @ensure(lambda result: (result[0] is None) ^ (result[1] is None))
806
+ def _ann_assign_to_property(
807
+ node: ast.AnnAssign, description: Optional[Description], atok: asttokens.ASTTokens
808
+ ) -> Tuple[Optional[Property], Optional[Error]]:
809
+ if not isinstance(node.target, ast.Name):
810
+ return (
811
+ None,
812
+ Error(
813
+ node.target,
814
+ f"Expected property target to be a name, "
815
+ f"but got: {atok.get_text(node.target)}",
816
+ ),
817
+ )
818
+
819
+ if not node.simple:
820
+ return (
821
+ None,
822
+ Error(
823
+ node.target,
824
+ "Expected a property with a simple target (no parentheses!)",
825
+ ),
826
+ )
827
+
828
+ if node.annotation is None:
829
+ return (
830
+ None,
831
+ Error(node.target, "Expected property to be annotated with a type"),
832
+ )
833
+
834
+ type_annotation, error = _type_annotation(node=node.annotation, atok=atok)
835
+ if error is not None:
836
+ return None, error
837
+
838
+ assert type_annotation is not None
839
+
840
+ if node.value is not None:
841
+ return (
842
+ None,
843
+ Error(node.value, "Unexpected assignment of a value to a property"),
844
+ )
845
+
846
+ return (
847
+ Property(
848
+ name=Identifier(node.target.id),
849
+ type_annotation=type_annotation,
850
+ description=description,
851
+ node=node,
852
+ ),
853
+ None,
854
+ )
855
+
856
+
857
+ # noinspection PyTypeChecker
858
+ @ensure(lambda result: (result[0] is None) ^ (result[1] is None))
859
+ def _args_to_arguments(
860
+ node: ast.arguments, atok: asttokens.ASTTokens
861
+ ) -> Tuple[Optional[List[Argument]], Optional[Error]]:
862
+ """Parse arguments of a method."""
863
+ if hasattr(node, "posonlyargs") and len(node.posonlyargs) > 0:
864
+ return None, Error(node, "Unexpected positional-only arguments")
865
+
866
+ if node.vararg is not None or node.kwarg is not None:
867
+ return None, Error(node, "Unexpected variable arguments")
868
+
869
+ if len(node.kwonlyargs) > 0:
870
+ return None, Error(node, "Unexpected keyword-only arguments")
871
+
872
+ assert len(node.kw_defaults) == 0, (
873
+ "No keyword-only arguments implies "
874
+ "there should be no defaults "
875
+ "for keyword-only arguments either."
876
+ )
877
+
878
+ if len(node.args) == 0:
879
+ return None, Error(node, "Unexpected no arguments")
880
+
881
+ arguments = [] # type: List[Argument]
882
+
883
+ # region ``self``
884
+
885
+ found_self = False
886
+
887
+ if len(node.args) >= 1 and node.args[0].arg == "self":
888
+ found_self = True
889
+
890
+ if node.args[0].annotation is not None:
891
+ return (
892
+ None,
893
+ Error(
894
+ node.args[0],
895
+ "Unexpected type annotation for the method argument ``self``",
896
+ ),
897
+ )
898
+
899
+ if len(node.defaults) == len(node.args):
900
+ return (
901
+ None,
902
+ Error(
903
+ node.args[0],
904
+ "Unexpected default value for the method argument ``self``",
905
+ ),
906
+ )
907
+
908
+ arguments.append(
909
+ Argument(
910
+ name=Identifier("self"),
911
+ type_annotation=SelfTypeAnnotation(),
912
+ default=None,
913
+ node=node.args[0],
914
+ )
915
+ )
916
+
917
+ # endregion
918
+
919
+ # region Non-self arguments
920
+
921
+ # We skip the first argument if we found ``self`` as it has been added to
922
+ # ``arguments`` already.
923
+
924
+ for i in range(1 if found_self else 0, len(node.args)):
925
+ arg_node = node.args[i]
926
+
927
+ # region Type annotation
928
+ if arg_node.annotation is None:
929
+ return (
930
+ None,
931
+ Error(
932
+ arg_node,
933
+ f"Unexpected method argument without a type annotation: "
934
+ f"{arg_node.arg}",
935
+ ),
936
+ )
937
+
938
+ type_annotation, error = _type_annotation(node=arg_node.annotation, atok=atok)
939
+ if error is not None:
940
+ return (
941
+ None,
942
+ Error(
943
+ arg_node,
944
+ f"Failed to parse the type annotation "
945
+ f"of the method argument {arg_node.arg}: "
946
+ f"{atok.get_text(arg_node.annotation)}",
947
+ underlying=[error],
948
+ ),
949
+ )
950
+
951
+ assert type_annotation is not None
952
+
953
+ # endregion
954
+
955
+ # region Default
956
+ default = None # type: Optional[Default]
957
+
958
+ # NOTE (mristin, 2021-12-16):
959
+ # A simple hypothetical test calculation:
960
+ # 5 args
961
+ # 2 defaults
962
+ #
963
+ # i = 3
964
+ # i - offset = 0 🠒 index in the node.defaults
965
+ # offset must be 3
966
+ # offset = len(node.args) - len(node.defaults) = 5 - 2 = 3
967
+
968
+ offset = len(node.args) - len(node.defaults)
969
+ if i >= offset:
970
+ default = Default(node=node.defaults[i - offset])
971
+
972
+ # endregion
973
+
974
+ arguments.append(
975
+ Argument(
976
+ name=Identifier(arg_node.arg),
977
+ type_annotation=type_annotation,
978
+ default=default,
979
+ node=arg_node,
980
+ )
981
+ )
982
+
983
+ # endregion
984
+
985
+ return arguments, None
986
+
987
+
988
+ # noinspection PyTypeChecker
989
+ @ensure(lambda result: (result[0] is None) ^ (result[1] is None))
990
+ def _parse_contract_condition(
991
+ node: ast.Call, atok: asttokens.ASTTokens
992
+ ) -> Tuple[Optional[Contract], Optional[Error]]:
993
+ """Parse the contract decorator."""
994
+ condition_node = None # type: Optional[ast.AST]
995
+ description_node = None # type: Optional[ast.AST]
996
+
997
+ if len(node.args) >= 1:
998
+ condition_node = node.args[0]
999
+
1000
+ if len(node.args) >= 2:
1001
+ description_node = node.args[1]
1002
+
1003
+ for keyword in node.keywords:
1004
+ if keyword.arg == "condition":
1005
+ condition_node = keyword.value
1006
+
1007
+ elif keyword.arg == "description":
1008
+ description_node = keyword.value
1009
+
1010
+ else:
1011
+ # We simply ignore to parse the argument.
1012
+ pass
1013
+
1014
+ if condition_node is None:
1015
+ return (
1016
+ None,
1017
+ Error(node, "Expected the condition to be defined for a contract"),
1018
+ )
1019
+
1020
+ if not isinstance(condition_node, ast.Lambda):
1021
+ return (
1022
+ None,
1023
+ Error(
1024
+ condition_node,
1025
+ f"Expected a lambda function as a contract condition, "
1026
+ f"but got: {atok.get_text(condition_node)}",
1027
+ ),
1028
+ )
1029
+
1030
+ description = None # type: Optional[str]
1031
+ if description_node is not None:
1032
+ if not (
1033
+ isinstance(description_node, ast.Constant)
1034
+ and isinstance(description_node.value, str)
1035
+ ):
1036
+ return (
1037
+ None,
1038
+ Error(
1039
+ description_node,
1040
+ f"Expected a string literal as a contract description, "
1041
+ f"but got: {atok.get_text(description_node)!r}",
1042
+ ),
1043
+ )
1044
+
1045
+ description = description_node.value
1046
+
1047
+ body, error = _rules.ast_node_to_our_node(node=condition_node.body)
1048
+ if error is not None:
1049
+ return None, Error(condition_node.body, "Failed to parse the contract", [error])
1050
+
1051
+ assert body is not None
1052
+
1053
+ if not isinstance(body, tree.Expression):
1054
+ return None, Error(
1055
+ condition_node.body,
1056
+ f"Expected an expression in the contract condition body, "
1057
+ f"but got: {tree.dump(body)}",
1058
+ )
1059
+
1060
+ return (
1061
+ Contract(
1062
+ args=[Identifier(arg.arg) for arg in condition_node.args.args],
1063
+ description=description,
1064
+ body=body,
1065
+ node=node,
1066
+ ),
1067
+ None,
1068
+ )
1069
+
1070
+
1071
+ # noinspection PyTypeChecker
1072
+ @ensure(lambda result: (result[0] is None) ^ (result[1] is None))
1073
+ def _parse_snapshot(
1074
+ node: ast.Call, atok: asttokens.ASTTokens
1075
+ ) -> Tuple[Optional[Snapshot], Optional[Error]]:
1076
+ """Parse the snapshot decorator."""
1077
+ capture_node = None # type: Optional[ast.AST]
1078
+ name_node = None # type: Optional[ast.AST]
1079
+
1080
+ if len(node.args) >= 1:
1081
+ capture_node = node.args[0]
1082
+
1083
+ if len(node.args) >= 2:
1084
+ name_node = node.args[1]
1085
+
1086
+ for keyword in node.keywords:
1087
+ if keyword.arg == "capture":
1088
+ capture_node = keyword.value
1089
+
1090
+ elif keyword.arg == "name":
1091
+ name_node = keyword.value
1092
+
1093
+ else:
1094
+ # We simply ignore to parse the argument.
1095
+ pass
1096
+
1097
+ if capture_node is None:
1098
+ return None, Error(node, "Expected the capture to be defined for a snapshot")
1099
+
1100
+ if not isinstance(capture_node, ast.Lambda):
1101
+ return (
1102
+ None,
1103
+ Error(
1104
+ capture_node,
1105
+ f"Expected a lambda function as a capture of a snapshot, "
1106
+ f"but got: {atok.get_text(capture_node)}",
1107
+ ),
1108
+ )
1109
+
1110
+ if name_node is not None and not (
1111
+ isinstance(name_node, ast.Constant) and isinstance(name_node.value, str)
1112
+ ):
1113
+ return (
1114
+ None,
1115
+ Error(
1116
+ name_node,
1117
+ f"Expected a string literal as a capture name, "
1118
+ f"but got: {atok.get_text(name_node)}",
1119
+ ),
1120
+ )
1121
+
1122
+ if name_node is not None:
1123
+ name = name_node.value
1124
+ elif len(capture_node.args.args) == 1 and name_node is None:
1125
+ name = capture_node.args.args[0].arg
1126
+ else:
1127
+ return (
1128
+ None,
1129
+ Error(
1130
+ node,
1131
+ "Expected the name of the snapshot to be defined, "
1132
+ "but there was neither the single argument in the capture "
1133
+ "nor explicit ``name`` given",
1134
+ ),
1135
+ )
1136
+
1137
+ if not IDENTIFIER_RE.fullmatch(name):
1138
+ return (
1139
+ None,
1140
+ Error(
1141
+ name_node if name_node is not None else node,
1142
+ f"Expected a capture name to be a valid identifier, but got: {name!r}",
1143
+ ),
1144
+ )
1145
+
1146
+ body, error = _rules.ast_node_to_our_node(node=capture_node.body)
1147
+ if error is not None:
1148
+ return None, Error(capture_node.body, "Failed to parse the snapshot", [error])
1149
+
1150
+ assert body is not None
1151
+
1152
+ if not isinstance(body, tree.Expression):
1153
+ return None, Error(
1154
+ capture_node.body,
1155
+ f"Expected an expression in the contract condition body, "
1156
+ f"but got: {tree.dump(body)}",
1157
+ )
1158
+
1159
+ return (
1160
+ Snapshot(
1161
+ args=[Identifier(arg.arg) for arg in capture_node.args.args],
1162
+ name=Identifier(name),
1163
+ body=body,
1164
+ node=node,
1165
+ ),
1166
+ None,
1167
+ )
1168
+
1169
+
1170
+ # fmt: off
1171
+ # noinspection PyTypeChecker,PyUnresolvedReferences
1172
+ @ensure(
1173
+ lambda expect_self, result:
1174
+ not (result[0] is not None and not expect_self)
1175
+ or 'self' not in result[0].arguments_by_name,
1176
+ "No ``self`` argument if not ``expect_self``"
1177
+ )
1178
+ @ensure(
1179
+ lambda expect_self, result:
1180
+ not (result[0] is not None and expect_self)
1181
+ or (
1182
+ len(result[0].arguments) >= 0
1183
+ and result[0].arguments[0].name == 'self'
1184
+ and isinstance(result[0].arguments[0].type_annotation, SelfTypeAnnotation)
1185
+ ),
1186
+ "If ``expect_self`` set, expect at least one argument and that should be ``self``"
1187
+ )
1188
+ @ensure(lambda result: (result[0] is None) ^ (result[1] is None))
1189
+ # fmt: on
1190
+ def _function_def_to_method(
1191
+ node: ast.FunctionDef, expect_self: bool, atok: asttokens.ASTTokens
1192
+ ) -> Tuple[Optional[MethodUnion], Optional[Error]]:
1193
+ """
1194
+ Parse the function definition into a method.
1195
+
1196
+ Though we have to distinguish in Python between a function and a method, we term
1197
+ both of them "methods" in our model.
1198
+
1199
+ If ``expect_self`` is set, the first argument is expected to be ``self``. Otherwise,
1200
+ no ``self`` argument is expected.
1201
+ """
1202
+ # NOTE (mristin, 2021-12-19):
1203
+ # This run-time check is necessary as we already burned our fingers with it.
1204
+ assert isinstance(node, ast.FunctionDef)
1205
+
1206
+ name = node.name
1207
+
1208
+ if name != "__init__" and name.startswith("__") and name.endswith("__"):
1209
+ return (
1210
+ None,
1211
+ Error(
1212
+ node,
1213
+ f"Among all dunder methods, only ``__init__`` is expected, "
1214
+ f"but got: {name}",
1215
+ ),
1216
+ )
1217
+
1218
+ preconditions = [] # type: List[Contract]
1219
+ postconditions = [] # type: List[Contract]
1220
+ snapshots = [] # type: List[Snapshot]
1221
+
1222
+ is_implementation_specific = False
1223
+ verification = False # Set if the function is decorated with ``@verification``
1224
+ non_mutating = False # Set if the function is decorated with ``@non_mutating``
1225
+
1226
+ # region Parse decorators
1227
+
1228
+ for decorator in node.decorator_list:
1229
+ if isinstance(decorator, ast.Call):
1230
+ if isinstance(decorator.func, ast.Name):
1231
+ if decorator.func.id == "require":
1232
+ precondition, error = _parse_contract_condition(
1233
+ node=decorator, atok=atok
1234
+ )
1235
+ if error is not None:
1236
+ return None, error
1237
+
1238
+ assert precondition is not None
1239
+
1240
+ preconditions.append(precondition)
1241
+
1242
+ elif decorator.func.id == "ensure":
1243
+ postcondition, error = _parse_contract_condition(
1244
+ node=decorator, atok=atok
1245
+ )
1246
+ if error is not None:
1247
+ return None, error
1248
+
1249
+ assert postcondition is not None
1250
+
1251
+ postconditions.append(postcondition)
1252
+
1253
+ elif decorator.func.id == "snapshot":
1254
+ snapshot, error = _parse_snapshot(node=decorator, atok=atok)
1255
+ if error is not None:
1256
+ return None, error
1257
+
1258
+ assert snapshot is not None
1259
+
1260
+ snapshots.append(snapshot)
1261
+
1262
+ else:
1263
+ return (
1264
+ None,
1265
+ Error(
1266
+ decorator,
1267
+ f"Unexpected decorator of a method: {decorator.func.id}; "
1268
+ f"expected at most "
1269
+ f"``require``, ``ensure`` or ``snapshot``",
1270
+ ),
1271
+ )
1272
+ else:
1273
+ return (
1274
+ None,
1275
+ Error(
1276
+ decorator,
1277
+ f"Unexpected non-name decorator of a method: "
1278
+ f"{atok.get_text(decorator.func)!r}",
1279
+ ),
1280
+ )
1281
+
1282
+ elif isinstance(decorator, ast.Name):
1283
+ if decorator.id == "implementation_specific":
1284
+ is_implementation_specific = True
1285
+
1286
+ elif decorator.id == "verification":
1287
+ verification = True
1288
+
1289
+ elif decorator.id == "non_mutating":
1290
+ non_mutating = True
1291
+
1292
+ else:
1293
+ return (
1294
+ None,
1295
+ Error(
1296
+ decorator,
1297
+ f"Unexpected simple decorator of a method: {decorator.id}; "
1298
+ f"expected at most ``implementation_specific``",
1299
+ ),
1300
+ )
1301
+ else:
1302
+ return (
1303
+ None,
1304
+ Error(
1305
+ decorator,
1306
+ f"Expected decorators of a method to be "
1307
+ f"only ``ast.Name`` and ``ast.Call``, "
1308
+ f"but got: {atok.get_text(decorator)!r}",
1309
+ ),
1310
+ )
1311
+
1312
+ # endregion
1313
+
1314
+ # region Reverse contracts
1315
+
1316
+ # We need to reverse the contracts since the decorators are evaluated from bottom
1317
+ # up, while we parsed them from top to bottom.
1318
+ preconditions = list(reversed(preconditions))
1319
+ snapshots = list(reversed(snapshots))
1320
+ postconditions = list(reversed(postconditions))
1321
+
1322
+ # endregion
1323
+
1324
+ # region Parse arguments and body
1325
+
1326
+ description = None # type: Optional[Description]
1327
+ body = node.body
1328
+
1329
+ if len(node.body) >= 1 and is_string_expr(expr=node.body[0]):
1330
+ assert isinstance(node.body[0], ast.Expr)
1331
+ assert isinstance(node.body[0].value, ast.Constant)
1332
+
1333
+ description, error = _ast_constant_string_to_description(
1334
+ constant=node.body[0].value
1335
+ )
1336
+
1337
+ if error is not None:
1338
+ return None, error
1339
+
1340
+ body = node.body[1:]
1341
+
1342
+ arguments, error = _args_to_arguments(node=node.args, atok=atok)
1343
+ if error is not None:
1344
+ return (
1345
+ None,
1346
+ Error(
1347
+ node,
1348
+ f"Failed to parse arguments of the method: {name}",
1349
+ underlying=[error],
1350
+ ),
1351
+ )
1352
+
1353
+ assert arguments is not None
1354
+
1355
+ returns = None # type: Optional[TypeAnnotation]
1356
+ if node.returns is None:
1357
+ return (
1358
+ None,
1359
+ Error(
1360
+ node,
1361
+ f"Unexpected method without a type annotation for the result: {name}",
1362
+ ),
1363
+ )
1364
+
1365
+ if not (isinstance(node.returns, ast.Constant) and node.returns.value is None):
1366
+ returns, error = _type_annotation(node=node.returns, atok=atok)
1367
+ if error is not None:
1368
+ return None, error
1369
+
1370
+ # endregion
1371
+
1372
+ # region All contract arguments are included in the function arguments
1373
+
1374
+ function_arg_set = set(arg.name for arg in arguments)
1375
+
1376
+ for contract in preconditions:
1377
+ for arg in contract.args:
1378
+ if arg not in function_arg_set:
1379
+ return (
1380
+ None,
1381
+ Error(
1382
+ contract.node,
1383
+ f"The argument of the precondition is not provided "
1384
+ f"in the method: {arg}",
1385
+ ),
1386
+ )
1387
+
1388
+ has_snapshots = len(snapshots) > 0
1389
+ for contract in postconditions:
1390
+ for arg in contract.args:
1391
+ if arg == "OLD":
1392
+ if not has_snapshots and arg == "OLD":
1393
+ return (
1394
+ None,
1395
+ Error(
1396
+ contract.node,
1397
+ f"The argument OLD of the postcondition is not provided "
1398
+ f"since there were no snapshots defined "
1399
+ f"for the method: {name}",
1400
+ ),
1401
+ )
1402
+
1403
+ elif arg == "result":
1404
+ continue
1405
+
1406
+ elif arg not in function_arg_set:
1407
+ return (
1408
+ None,
1409
+ Error(
1410
+ contract.node,
1411
+ f"The argument of the postcondition is not provided "
1412
+ f"in the method: {arg}",
1413
+ ),
1414
+ )
1415
+ else:
1416
+ # Everything is OK.
1417
+ pass
1418
+
1419
+ for snapshot in snapshots:
1420
+ for arg in snapshot.args:
1421
+ if arg not in function_arg_set:
1422
+ return (
1423
+ None,
1424
+ Error(
1425
+ snapshot.node,
1426
+ f"The argument of the snapshot is not provided "
1427
+ f"in the method: {arg}",
1428
+ ),
1429
+ )
1430
+
1431
+ # endregion
1432
+
1433
+ # region Check __init__ constraints
1434
+ if name == "__init__":
1435
+ # Must return None
1436
+ if returns is not None:
1437
+ return (
1438
+ None,
1439
+ Error(
1440
+ node,
1441
+ f"Expected __init__ to return None, "
1442
+ f"but got: {atok.get_text(node.returns)}",
1443
+ ),
1444
+ )
1445
+
1446
+ # Must not be a verification
1447
+ if verification:
1448
+ return (
1449
+ None,
1450
+ Error(
1451
+ node,
1452
+ "Expected __init__ not to be a verification function",
1453
+ ),
1454
+ )
1455
+
1456
+ # endregion
1457
+
1458
+ # region Check that the parsed method conforms to ``expect_self``
1459
+
1460
+ if expect_self and len(arguments) == 0:
1461
+ return (
1462
+ None,
1463
+ Error(
1464
+ node,
1465
+ f"A ``self`` argument is expected, but no arguments were specified "
1466
+ f"in the method {name!r}",
1467
+ ),
1468
+ )
1469
+
1470
+ if expect_self and len(arguments) >= 1:
1471
+ if arguments[0].name != "self":
1472
+ return (
1473
+ None,
1474
+ Error(
1475
+ node,
1476
+ f"Expected the first argument to be ``self`` "
1477
+ f"in the method {name!r}, but got {arguments[0].name!r}",
1478
+ ),
1479
+ )
1480
+
1481
+ if not isinstance(arguments[0].type_annotation, SelfTypeAnnotation):
1482
+ return (
1483
+ None,
1484
+ Error(
1485
+ node,
1486
+ f"Expected the ``self`` argument to have no annotation "
1487
+ f"in the method {name!r}, but got {arguments[0].type_annotation!r}",
1488
+ ),
1489
+ )
1490
+
1491
+ # endregion
1492
+
1493
+ if is_implementation_specific:
1494
+ return (
1495
+ ImplementationSpecificMethod(
1496
+ name=Identifier(name),
1497
+ verification=verification,
1498
+ arguments=arguments,
1499
+ returns=returns,
1500
+ description=description,
1501
+ contracts=Contracts(
1502
+ preconditions=preconditions,
1503
+ snapshots=snapshots,
1504
+ postconditions=postconditions,
1505
+ ),
1506
+ non_mutating=non_mutating,
1507
+ node=node,
1508
+ ),
1509
+ None,
1510
+ )
1511
+ else:
1512
+ if name == "__init__":
1513
+ assert not verification
1514
+ assert returns is None
1515
+
1516
+ if non_mutating:
1517
+ return (
1518
+ None,
1519
+ Error(
1520
+ node,
1521
+ "Unexpected non-mutating constructor",
1522
+ ),
1523
+ )
1524
+
1525
+ return (
1526
+ ConstructorToBeUnderstood(
1527
+ arguments=arguments,
1528
+ description=description,
1529
+ contracts=Contracts(
1530
+ preconditions=preconditions,
1531
+ snapshots=snapshots,
1532
+ postconditions=postconditions,
1533
+ ),
1534
+ body=body,
1535
+ node=node,
1536
+ ),
1537
+ None,
1538
+ )
1539
+ else:
1540
+ understanding_errors = [] # type: List[Error]
1541
+
1542
+ understood_body = [] # type: List[tree.Node]
1543
+
1544
+ for body_child in body:
1545
+ # NOTE (mristin, 2021-12-27):
1546
+ # We deliberately ignore ``pass`` as it makes no sense in our
1547
+ # context of multiple programming languages.
1548
+ if isinstance(body_child, ast.Pass):
1549
+ continue
1550
+
1551
+ understood_node, understanding_error = _rules.ast_node_to_our_node(
1552
+ body_child
1553
+ )
1554
+
1555
+ if understanding_error is not None:
1556
+ understanding_errors.append(understanding_error)
1557
+ continue
1558
+
1559
+ assert understood_node is not None
1560
+ understood_body.append(understood_node)
1561
+
1562
+ if len(understanding_errors) > 0:
1563
+ return None, Error(
1564
+ node,
1565
+ f"Failed to understand the body of the function {name!r}",
1566
+ understanding_errors,
1567
+ )
1568
+
1569
+ return (
1570
+ UnderstoodMethod(
1571
+ name=Identifier(name),
1572
+ verification=verification,
1573
+ arguments=arguments,
1574
+ returns=returns,
1575
+ description=description,
1576
+ contracts=Contracts(
1577
+ preconditions=preconditions,
1578
+ snapshots=snapshots,
1579
+ postconditions=postconditions,
1580
+ ),
1581
+ non_mutating=non_mutating,
1582
+ body=understood_body,
1583
+ node=node,
1584
+ ),
1585
+ None,
1586
+ )
1587
+
1588
+
1589
+ class _ClassMarker(enum.Enum):
1590
+ ABSTRACT = "abstract"
1591
+ IMPLEMENTATION_SPECIFIC = "implementation_specific"
1592
+ TEMPLATE = "template"
1593
+
1594
+
1595
+ _CLASS_MARKER_FROM_STRING: Mapping[str, _ClassMarker] = {
1596
+ marker.value: marker for marker in _ClassMarker
1597
+ }
1598
+
1599
+
1600
+ @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
1601
+ def _class_decorator_to_marker(
1602
+ decorator: ast.Name,
1603
+ ) -> Tuple[Optional[_ClassMarker], Optional[Error]]:
1604
+ """Parse a simple decorator as a class marker."""
1605
+ class_marker = _CLASS_MARKER_FROM_STRING.get(decorator.id, None)
1606
+
1607
+ if class_marker is None:
1608
+ return (
1609
+ None,
1610
+ Error(
1611
+ decorator,
1612
+ f"The handling of the marker has not been "
1613
+ f"implemented: {decorator.id!r}",
1614
+ ),
1615
+ )
1616
+
1617
+ return class_marker, None
1618
+
1619
+
1620
+ # fmt: off
1621
+ # noinspection PyTypeChecker
1622
+ @require(
1623
+ lambda decorator:
1624
+ isinstance(decorator.func, ast.Name)
1625
+ and isinstance(decorator.func.ctx, ast.Load)
1626
+ and decorator.func.id == 'serialization'
1627
+ )
1628
+ @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
1629
+ # fmt: on
1630
+ def _class_decorator_to_serialization(
1631
+ decorator: ast.Call,
1632
+ ) -> Tuple[Optional[Serialization], Optional[Error]]:
1633
+ """Translate a decorator to general serialization settings."""
1634
+ with_model_type_node = None # type: Optional[ast.AST]
1635
+
1636
+ if len(decorator.args) >= 1:
1637
+ with_model_type_node = decorator.args[0]
1638
+
1639
+ if len(decorator.keywords) > 0:
1640
+ for kwarg in decorator.keywords:
1641
+ if kwarg.arg == "with_model_type":
1642
+ with_model_type_node = kwarg.value
1643
+ else:
1644
+ return (
1645
+ None,
1646
+ Error(
1647
+ decorator,
1648
+ f"Handling of the keyword argument {kwarg.arg!r} "
1649
+ f"for the serialization decorator has not been implemented",
1650
+ ),
1651
+ )
1652
+
1653
+ with_model_type = None # type: Optional[bool]
1654
+ if with_model_type_node is not None:
1655
+ if not isinstance(with_model_type_node, ast.Constant):
1656
+ return (
1657
+ None,
1658
+ Error(
1659
+ with_model_type_node,
1660
+ f"Expected the value for ``with_model_type`` parameter "
1661
+ f"to be a constant, but got: {ast.dump(with_model_type_node)}",
1662
+ ),
1663
+ )
1664
+
1665
+ if not isinstance(with_model_type_node.value, bool):
1666
+ return (
1667
+ None,
1668
+ Error(
1669
+ with_model_type_node,
1670
+ f"Expected the value for ``with_model_type`` parameter "
1671
+ f"to be a boolean, but got: {with_model_type_node.value}",
1672
+ ),
1673
+ )
1674
+
1675
+ with_model_type = with_model_type_node.value
1676
+
1677
+ return Serialization(with_model_type=with_model_type), None
1678
+
1679
+
1680
+ # fmt: off
1681
+ # noinspection PyTypeChecker
1682
+ @require(
1683
+ lambda decorator:
1684
+ isinstance(decorator.func, ast.Name)
1685
+ and isinstance(decorator.func.ctx, ast.Load)
1686
+ and decorator.func.id == 'invariant'
1687
+ )
1688
+ @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
1689
+ # fmt: on
1690
+ def _class_decorator_to_invariant(
1691
+ decorator: ast.Call, atok: asttokens.ASTTokens
1692
+ ) -> Tuple[Optional[Invariant], Optional[Error]]:
1693
+ """Parse the decorator node as a class invariant."""
1694
+ condition_node = None # type: Optional[ast.AST]
1695
+ description_node = None # type: Optional[ast.AST]
1696
+
1697
+ if len(decorator.args) >= 1:
1698
+ condition_node = decorator.args[0]
1699
+
1700
+ if len(decorator.args) >= 2:
1701
+ description_node = decorator.args[1]
1702
+
1703
+ if len(decorator.keywords) > 0:
1704
+ for kwarg in decorator.keywords:
1705
+ if kwarg.arg == "condition":
1706
+ condition_node = kwarg.value
1707
+ elif kwarg.arg == "description":
1708
+ description_node = kwarg.value
1709
+ else:
1710
+ return (
1711
+ None,
1712
+ Error(
1713
+ decorator,
1714
+ f"Handling of the keyword argument {kwarg.arg!r} "
1715
+ f"for the invariant has not been implemented",
1716
+ ),
1717
+ )
1718
+
1719
+ if not isinstance(condition_node, ast.Lambda):
1720
+ return (
1721
+ None,
1722
+ Error(
1723
+ decorator,
1724
+ f"Expected the condition of an invariant to be a lambda, "
1725
+ f"but got {type(condition_node)}: {atok.get_text(decorator)}",
1726
+ ),
1727
+ )
1728
+
1729
+ if description_node is None:
1730
+ return (
1731
+ None,
1732
+ Error(decorator, "The invariant must have a human-readable description"),
1733
+ )
1734
+
1735
+ if not isinstance(description_node, ast.Constant) or not isinstance(
1736
+ description_node.value, str
1737
+ ):
1738
+ return (
1739
+ None,
1740
+ Error(
1741
+ decorator,
1742
+ f"Expected the description of an invariant to be "
1743
+ f"a string literal, but got: {type(description_node)}",
1744
+ ),
1745
+ )
1746
+
1747
+ if len(condition_node.args.args) != 1 or condition_node.args.args[0].arg != "self":
1748
+ return (
1749
+ None,
1750
+ Error(
1751
+ decorator, "Expected the invariant to have a single argument, ``self``"
1752
+ ),
1753
+ )
1754
+
1755
+ body, error = _rules.ast_node_to_our_node(node=condition_node.body)
1756
+ if error is not None:
1757
+ return None, Error(
1758
+ condition_node.body, "Failed to parse the invariant", [error]
1759
+ )
1760
+
1761
+ assert body is not None
1762
+
1763
+ if not isinstance(body, tree.Expression):
1764
+ return None, Error(
1765
+ condition_node.body,
1766
+ f"Expected an expression in an invariant, but got: {tree.dump(body)}",
1767
+ )
1768
+
1769
+ return (
1770
+ Invariant(
1771
+ description=description_node.value,
1772
+ body=body,
1773
+ node=decorator,
1774
+ ),
1775
+ None,
1776
+ )
1777
+
1778
+
1779
+ _ClassDecoratorUnion = Union[
1780
+ _ClassMarker,
1781
+ Serialization,
1782
+ Invariant,
1783
+ ]
1784
+
1785
+
1786
+ # noinspection PyTypeChecker
1787
+ @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
1788
+ def _parse_class_decorator(
1789
+ decorator: ast.AST, atok: asttokens.ASTTokens
1790
+ ) -> Tuple[Optional[_ClassDecoratorUnion], Optional[Error]]:
1791
+ """
1792
+ Parse a class decorator.
1793
+
1794
+ The decorator needs to be further interpreted in the context of the class.
1795
+ The class here refers to a general Python class, not the concrete or abstract
1796
+ class of the meta-model. For example, an enumeration is also defined as a Python
1797
+ class inheriting from ``Enum``.
1798
+ """
1799
+ if isinstance(decorator, ast.Name):
1800
+ return _class_decorator_to_marker(decorator=decorator)
1801
+ elif isinstance(decorator, ast.Call):
1802
+ if not isinstance(decorator.func, ast.Name):
1803
+ return None, Error(
1804
+ decorator,
1805
+ f"Expected a name for a decorator function, "
1806
+ f"but got: {ast.dump(decorator.func)}",
1807
+ )
1808
+
1809
+ if not isinstance(decorator.func.ctx, ast.Load):
1810
+ return None, Error(
1811
+ decorator,
1812
+ f"Unexpected decorator function in "
1813
+ f"a non-Load context: {decorator.func.ctx=}",
1814
+ )
1815
+
1816
+ if decorator.func.id == "serialization":
1817
+ return _class_decorator_to_serialization(decorator=decorator)
1818
+ elif decorator.func.id == "invariant":
1819
+ return _class_decorator_to_invariant(decorator=decorator, atok=atok)
1820
+ else:
1821
+ return None, Error(
1822
+ decorator,
1823
+ f"We do not know how to handle "
1824
+ f"the class decorator: {decorator.func.id}.",
1825
+ )
1826
+ else:
1827
+ return None, Error(
1828
+ decorator,
1829
+ f"Handling of a non-name or a non-call class decorator "
1830
+ f"has not been implemented: {ast.dump(decorator)}",
1831
+ )
1832
+
1833
+
1834
+ # noinspection PyTypeChecker,PyUnresolvedReferences
1835
+ @ensure(lambda result: (result[0] is None) ^ (result[1] is None))
1836
+ def _classdef_to_enumeration(
1837
+ node: ast.ClassDef, atok: asttokens.ASTTokens
1838
+ ) -> Tuple[Optional[Enumeration], Optional[Error]]:
1839
+ """Interpret a class which defines an enumeration."""
1840
+ for decorator_node in node.decorator_list:
1841
+ decorator, error = _parse_class_decorator(decorator=decorator_node, atok=atok)
1842
+ if error is not None:
1843
+ return None, error
1844
+ assert decorator is not None
1845
+
1846
+ return None, Error(
1847
+ node,
1848
+ f"Unexpected class decorator {decorator} "
1849
+ f"for the enumeration {node.name!r}",
1850
+ )
1851
+
1852
+ if len(node.body) == 0:
1853
+ return (
1854
+ Enumeration(
1855
+ name=Identifier(node.name),
1856
+ literals=[],
1857
+ description=None,
1858
+ node=node,
1859
+ ),
1860
+ None,
1861
+ )
1862
+
1863
+ enumeration_literals = [] # type: List[EnumerationLiteral]
1864
+
1865
+ description = None # type: Optional[Description]
1866
+
1867
+ cursor = 0
1868
+ while cursor < len(node.body):
1869
+ old_cursor = cursor
1870
+
1871
+ body_node = node.body[cursor] # type: ast.AST
1872
+
1873
+ if cursor == 0 and is_string_expr(body_node):
1874
+ assert isinstance(body_node, ast.Expr)
1875
+ assert isinstance(body_node.value, ast.Constant)
1876
+ description, error = _ast_constant_string_to_description(body_node.value)
1877
+ if error is not None:
1878
+ return None, error
1879
+
1880
+ cursor += 1
1881
+
1882
+ elif isinstance(body_node, ast.Pass):
1883
+ cursor += 1
1884
+
1885
+ elif isinstance(body_node, ast.Assign):
1886
+ assign = body_node
1887
+
1888
+ if len(assign.targets) != 1:
1889
+ return (
1890
+ None,
1891
+ Error(
1892
+ assign,
1893
+ f"Expected a single target in the assignment, "
1894
+ f"but got: {len(assign.targets)}",
1895
+ ),
1896
+ )
1897
+
1898
+ if not isinstance(assign.targets[0], ast.Name):
1899
+ return (
1900
+ None,
1901
+ Error(
1902
+ assign.targets[0],
1903
+ f"Expected a name as a target of the assignment, "
1904
+ f"but got: {assign.targets[0]}",
1905
+ ),
1906
+ )
1907
+
1908
+ if not isinstance(assign.value, ast.Constant):
1909
+ return (
1910
+ None,
1911
+ Error(
1912
+ assign.value,
1913
+ f"Expected a constant in the enumeration assignment, "
1914
+ f"but got: {atok.get_text(assign.value)}",
1915
+ ),
1916
+ )
1917
+
1918
+ if not isinstance(assign.value.value, str):
1919
+ return (
1920
+ None,
1921
+ Error(
1922
+ assign.value,
1923
+ f"Expected a string literal in the enumeration, "
1924
+ f"but got: {assign.value.value}",
1925
+ ),
1926
+ )
1927
+
1928
+ literal_name = Identifier(assign.targets[0].id)
1929
+ literal_value = assign.value.value
1930
+
1931
+ literal_description = None # type: Optional[Description]
1932
+ next_expr = node.body[cursor + 1] if cursor < len(node.body) - 1 else None
1933
+
1934
+ if next_expr is not None and is_string_expr(next_expr):
1935
+ assert isinstance(next_expr, ast.Expr)
1936
+ assert isinstance(next_expr.value, ast.Constant)
1937
+ literal_description, error = _ast_constant_string_to_description(
1938
+ next_expr.value
1939
+ )
1940
+
1941
+ if error is not None:
1942
+ return None, error
1943
+
1944
+ cursor += 1
1945
+
1946
+ enumeration_literals.append(
1947
+ EnumerationLiteral(
1948
+ name=literal_name,
1949
+ value=literal_value,
1950
+ description=literal_description,
1951
+ node=assign,
1952
+ )
1953
+ )
1954
+
1955
+ cursor += 1
1956
+
1957
+ else:
1958
+
1959
+ return (
1960
+ None,
1961
+ Error(
1962
+ node.body[cursor],
1963
+ f"Expected either a docstring at the beginning or an assignment "
1964
+ f"in an enumeration, "
1965
+ f"but got an unexpected body element at index {cursor} "
1966
+ f"of the class definition {node.name!r}: "
1967
+ f"{atok.get_text(node.body[cursor])}",
1968
+ ),
1969
+ )
1970
+
1971
+ assert cursor > old_cursor, f"Loop invariant: {cursor=}, {old_cursor=}"
1972
+
1973
+ return (
1974
+ Enumeration(
1975
+ name=Identifier(node.name),
1976
+ literals=enumeration_literals,
1977
+ description=description,
1978
+ node=node,
1979
+ ),
1980
+ None,
1981
+ )
1982
+
1983
+
1984
+ # noinspection PyTypeChecker
1985
+ @ensure(lambda result: (result[0] is None) ^ (result[1] is None))
1986
+ def _classdef_to_our_type(
1987
+ node: ast.ClassDef, atok: asttokens.ASTTokens
1988
+ ) -> Tuple[Optional[OurType], Optional[Error]]:
1989
+ """Interpret the class definition as our type."""
1990
+ underlying_errors = [] # type: List[Error]
1991
+
1992
+ base_names = [] # type: List[str]
1993
+ for base in node.bases:
1994
+ if not isinstance(base, ast.Name):
1995
+ underlying_errors.append(
1996
+ Error(
1997
+ base, f"Expected a base as a name, but got: {atok.get_text(base)}"
1998
+ )
1999
+ )
2000
+ else:
2001
+ base_names.append(base.id)
2002
+
2003
+ if len(underlying_errors) > 0:
2004
+ return (
2005
+ None,
2006
+ Error(
2007
+ node,
2008
+ f"Failed to parse the class definition: {node.name}",
2009
+ underlying=underlying_errors,
2010
+ ),
2011
+ )
2012
+
2013
+ if "Enum" in base_names and len(base_names) > 1:
2014
+ return (
2015
+ None,
2016
+ Error(
2017
+ node,
2018
+ f"Expected an enumeration to only inherit from ``Enum``, "
2019
+ f"but it inherits from: {base_names}",
2020
+ ),
2021
+ )
2022
+
2023
+ if "Enum" in base_names:
2024
+ return _classdef_to_enumeration(node=node, atok=atok)
2025
+
2026
+ # We have to parse the class definition from here on.
2027
+
2028
+ # DBC is only used for inheritance of the contracts in the meta-model
2029
+ # so that the developers tinkering with the meta-model can play with it
2030
+ # at runtime. We can safely ignore it as we are not looking into any
2031
+ # runtime code.
2032
+ inheritances = [
2033
+ Identifier(base_name) for base_name in base_names if base_name != "DBC"
2034
+ ]
2035
+
2036
+ # region Decorators
2037
+
2038
+ invariants = [] # type: List[Invariant]
2039
+
2040
+ is_abstract = False
2041
+ is_implementation_specific = False
2042
+
2043
+ serialization = None # type: Optional[Serialization]
2044
+
2045
+ for decorator_node in node.decorator_list:
2046
+ decorator, error = _parse_class_decorator(decorator=decorator_node, atok=atok)
2047
+ if error is not None:
2048
+ underlying_errors.append(error)
2049
+ continue
2050
+
2051
+ assert decorator is not None
2052
+ if isinstance(decorator, _ClassMarker):
2053
+ if decorator is _ClassMarker.ABSTRACT:
2054
+ is_abstract = True
2055
+ elif decorator is _ClassMarker.IMPLEMENTATION_SPECIFIC:
2056
+ is_implementation_specific = True
2057
+ elif decorator is _ClassMarker.TEMPLATE:
2058
+ # NOTE (mristin, 2021-11-28):
2059
+ # We ignore the template marker at this moment. However, we will most
2060
+ # probably have to consider them in the future, so we leave them in the
2061
+ # meta-model, but ignore them in the code generation.
2062
+ pass
2063
+
2064
+ else:
2065
+ assert_never(decorator)
2066
+
2067
+ elif isinstance(decorator, Serialization):
2068
+ if serialization is not None:
2069
+ underlying_errors.append(
2070
+ Error(decorator_node, "Unexpected double serialization markers")
2071
+ )
2072
+ continue
2073
+
2074
+ serialization = decorator
2075
+
2076
+ elif isinstance(decorator, Invariant):
2077
+ invariants.append(decorator)
2078
+
2079
+ else:
2080
+ assert_never(decorator)
2081
+
2082
+ if len(underlying_errors) > 0:
2083
+ return (
2084
+ None,
2085
+ Error(
2086
+ node,
2087
+ f"Failed to parse the class definition: {node.name}",
2088
+ underlying=underlying_errors,
2089
+ ),
2090
+ )
2091
+
2092
+ # NOTE (mristin, 20222-01-02):
2093
+ # We need to inverse the invariants as we collect them top-down, while
2094
+ # the decorators are applied bottom-up.
2095
+ invariants = list(reversed(invariants))
2096
+
2097
+ # endregion
2098
+
2099
+ if is_abstract and is_implementation_specific:
2100
+ return (
2101
+ None,
2102
+ Error(
2103
+ node,
2104
+ "Abstract classes can not be implementation-specific "
2105
+ "at the same time "
2106
+ "(otherwise we can not convert them to interfaces etc.)",
2107
+ ),
2108
+ )
2109
+
2110
+ description = None # type: Optional[Description]
2111
+
2112
+ properties = [] # type: List[Property]
2113
+ methods = [] # type: List[MethodUnion]
2114
+
2115
+ cursor = 0
2116
+ while cursor < len(node.body):
2117
+ old_cursor = cursor
2118
+
2119
+ expr = node.body[cursor]
2120
+
2121
+ if cursor == 0 and is_string_expr(expr):
2122
+ assert isinstance(expr, ast.Expr)
2123
+ assert isinstance(expr.value, ast.Constant)
2124
+ description, error = _ast_constant_string_to_description(expr.value)
2125
+ if error is not None:
2126
+ return None, error
2127
+
2128
+ assert description is not None
2129
+
2130
+ cursor += 1
2131
+ continue
2132
+
2133
+ if isinstance(expr, ast.Pass):
2134
+ cursor += 1
2135
+ continue
2136
+
2137
+ if isinstance(expr, ast.AnnAssign):
2138
+ description_of_property = None # type: Optional[Description]
2139
+
2140
+ next_expr = node.body[cursor + 1] if cursor < len(node.body) - 1 else None
2141
+ if next_expr is not None and is_string_expr(next_expr):
2142
+ assert isinstance(next_expr, ast.Expr)
2143
+ assert isinstance(next_expr.value, ast.Constant)
2144
+ description_of_property, error = _ast_constant_string_to_description(
2145
+ next_expr.value
2146
+ )
2147
+
2148
+ if error is not None:
2149
+ return None, error
2150
+
2151
+ assert description_of_property is not None
2152
+
2153
+ cursor += 1
2154
+
2155
+ prop, error = _ann_assign_to_property(
2156
+ node=expr, description=description_of_property, atok=atok
2157
+ )
2158
+ cursor += 1
2159
+
2160
+ if error is not None:
2161
+ return (
2162
+ None,
2163
+ Error(expr, "Failed to parse a property", underlying=[error]),
2164
+ )
2165
+
2166
+ assert prop is not None
2167
+
2168
+ properties.append(prop)
2169
+
2170
+ elif isinstance(expr, ast.FunctionDef):
2171
+ method, error = _function_def_to_method(
2172
+ node=expr, expect_self=True, atok=atok
2173
+ )
2174
+
2175
+ if error is not None:
2176
+ return (
2177
+ None,
2178
+ Error(
2179
+ expr,
2180
+ f"Failed to parse the method: {expr.name}",
2181
+ underlying=[error],
2182
+ ),
2183
+ )
2184
+
2185
+ assert method is not None
2186
+ methods.append(method)
2187
+
2188
+ cursor += 1
2189
+
2190
+ else:
2191
+ return (
2192
+ None,
2193
+ Error(
2194
+ expr,
2195
+ f"Expected only either "
2196
+ f"properties explicitly annotated with types or "
2197
+ f"instance methods, but got: {atok.get_text(expr)}",
2198
+ ),
2199
+ )
2200
+
2201
+ assert old_cursor < cursor, f"Loop invariant: {old_cursor=}, {cursor=}"
2202
+
2203
+ if is_abstract:
2204
+ factory_for_class = (
2205
+ AbstractClass
2206
+ ) # type: Union[Type[AbstractClass], Type[ConcreteClass]]
2207
+ else:
2208
+ factory_for_class = ConcreteClass
2209
+
2210
+ return (
2211
+ factory_for_class(
2212
+ name=Identifier(node.name),
2213
+ is_implementation_specific=is_implementation_specific,
2214
+ inheritances=inheritances,
2215
+ properties=properties,
2216
+ methods=methods,
2217
+ invariants=invariants,
2218
+ serialization=serialization,
2219
+ description=description,
2220
+ node=node,
2221
+ ),
2222
+ None,
2223
+ )
2224
+
2225
+
2226
+ def _verify_arity_of_type_annotation_subscript(
2227
+ type_annotation: SubscriptedTypeAnnotation,
2228
+ ) -> Optional[Error]:
2229
+ """
2230
+ Check that the subscripted type annotation has the expected number of arguments.
2231
+
2232
+ :return: error message, if any
2233
+ """
2234
+ expected_arity_map = {"List": 1, "Optional": 1}
2235
+ expected_arity = expected_arity_map.get(type_annotation.identifier, None)
2236
+ if expected_arity is None:
2237
+ raise AssertionError(
2238
+ f"Unexpected subscripted type annotation: {type_annotation}"
2239
+ )
2240
+
2241
+ assert expected_arity >= 0
2242
+ if len(type_annotation.subscripts) != expected_arity:
2243
+ return Error(
2244
+ type_annotation.node,
2245
+ f"Expected {expected_arity} arguments of "
2246
+ f"a subscripted type annotation {type_annotation.identifier!r}, "
2247
+ f"but got {len(type_annotation.subscripts)}: {type_annotation}",
2248
+ )
2249
+
2250
+ return None
2251
+
2252
+
2253
+ # fmt: off
2254
+ @ensure(
2255
+ lambda result:
2256
+ result[1] is None or len(result[1]) > 0,
2257
+ "If errors are not None, there must be at least one error"
2258
+ )
2259
+ @ensure(lambda result: (result[0] is None) ^ (result[1] is None))
2260
+ # fmt: on
2261
+ def _verify_symbol_table(
2262
+ symbol_table: UnverifiedSymbolTable,
2263
+ ) -> Tuple[Optional[SymbolTable], Optional[List[Error]]]:
2264
+ """
2265
+ Check that the symbol table is consistent.
2266
+
2267
+ For example, check that there are no dangling references in type annotations or
2268
+ inheritances.
2269
+ """
2270
+ errors = [] # type: List[Error]
2271
+
2272
+ # region Check reserved names
2273
+
2274
+ builtin_types_in_many_implementations = {
2275
+ "str",
2276
+ "string",
2277
+ "int",
2278
+ "integer",
2279
+ "float",
2280
+ "real",
2281
+ "decimal",
2282
+ "number",
2283
+ "bool",
2284
+ "boolean",
2285
+ "bytes",
2286
+ "bytearray",
2287
+ "object",
2288
+ "read_only",
2289
+ }
2290
+
2291
+ # noinspection SpellCheckingInspection
2292
+ keywords_in_many_implementations = (
2293
+ builtin_types_in_many_implementations.union(
2294
+ # Ada, see: https://en.wikibooks.org/wiki/Ada_Programming/Keywords
2295
+ #
2296
+ # We exclude ``type`` and ``range`` from the keywords as its usage in
2297
+ # the meta-model predates the generation of the Ada SDK, so it has been
2298
+ # missed, unfortunately.
2299
+ {
2300
+ "abort",
2301
+ "abs",
2302
+ "abstract",
2303
+ "accept",
2304
+ "access",
2305
+ "aliased",
2306
+ "all",
2307
+ "and",
2308
+ "array",
2309
+ "at",
2310
+ "begin",
2311
+ "body",
2312
+ "case",
2313
+ "constant",
2314
+ "declare",
2315
+ "delay",
2316
+ "delta",
2317
+ "digits",
2318
+ "do",
2319
+ "else",
2320
+ "elsif",
2321
+ "end",
2322
+ "entry",
2323
+ "exception",
2324
+ "exit",
2325
+ "for",
2326
+ "function",
2327
+ "generic",
2328
+ "goto",
2329
+ "if",
2330
+ "in",
2331
+ "interface",
2332
+ "is",
2333
+ "limited",
2334
+ "loop",
2335
+ "mod",
2336
+ "new",
2337
+ "not",
2338
+ "null",
2339
+ "of",
2340
+ "or",
2341
+ "others",
2342
+ "out",
2343
+ "overriding",
2344
+ "package",
2345
+ "pragma",
2346
+ "private",
2347
+ "procedure",
2348
+ "protected",
2349
+ "raise",
2350
+ "record",
2351
+ "rem",
2352
+ "renames",
2353
+ "requeue",
2354
+ "return",
2355
+ "reverse",
2356
+ "select",
2357
+ "separate",
2358
+ "some",
2359
+ "subtype",
2360
+ "synchronized",
2361
+ "tagged",
2362
+ "task",
2363
+ "terminate",
2364
+ "then",
2365
+ "until",
2366
+ "use",
2367
+ "when",
2368
+ "while",
2369
+ "with",
2370
+ "xor",
2371
+ }
2372
+ )
2373
+ .union(
2374
+ # C, see: https://en.cppreference.com/w/c/keyword
2375
+ {
2376
+ "auto",
2377
+ "break",
2378
+ "case",
2379
+ "char",
2380
+ "const",
2381
+ "continue",
2382
+ "default",
2383
+ "do",
2384
+ "double",
2385
+ "else",
2386
+ "enum",
2387
+ "extern",
2388
+ "float",
2389
+ "for",
2390
+ "goto",
2391
+ "if",
2392
+ "int",
2393
+ "long",
2394
+ "register",
2395
+ "return",
2396
+ "short",
2397
+ "signed",
2398
+ "sizeof",
2399
+ "static",
2400
+ "struct",
2401
+ "switch",
2402
+ "typedef",
2403
+ "union",
2404
+ "unsigned",
2405
+ "void",
2406
+ "volatile",
2407
+ "while",
2408
+ }
2409
+ )
2410
+ .union(
2411
+ # C++, see: https://en.cppreference.com/w/cpp/keyword
2412
+ {
2413
+ "alignas",
2414
+ "alignof",
2415
+ "and",
2416
+ "and_eq",
2417
+ "asm",
2418
+ "atomic_cancel",
2419
+ "atomic_commit",
2420
+ "atomic_noexcept",
2421
+ "auto",
2422
+ "bitand",
2423
+ "bitor",
2424
+ "bool",
2425
+ "break",
2426
+ "case",
2427
+ "catch",
2428
+ "char",
2429
+ "char16_t",
2430
+ "char32_t",
2431
+ "char8_t",
2432
+ "class",
2433
+ "co_await",
2434
+ "co_return",
2435
+ "co_yield",
2436
+ "compl",
2437
+ "concept",
2438
+ "const",
2439
+ "const_cast",
2440
+ "consteval",
2441
+ "constexpr",
2442
+ "constinit",
2443
+ "continue",
2444
+ "decltype",
2445
+ "default",
2446
+ "delete",
2447
+ "do",
2448
+ "double",
2449
+ "dynamic_cast",
2450
+ "else",
2451
+ "enum",
2452
+ "explicit",
2453
+ "export",
2454
+ "extern",
2455
+ "false",
2456
+ "float",
2457
+ "for",
2458
+ "friend",
2459
+ "goto",
2460
+ "if",
2461
+ "inline",
2462
+ "int",
2463
+ "long",
2464
+ "mutable",
2465
+ "namespace",
2466
+ "new",
2467
+ "noexcept",
2468
+ "not",
2469
+ "not_eq",
2470
+ "nullptr",
2471
+ "operator",
2472
+ "or",
2473
+ "or_eq",
2474
+ "private",
2475
+ "protected",
2476
+ "public",
2477
+ "reflexpr",
2478
+ "register",
2479
+ "reinterpret_cast",
2480
+ "requires",
2481
+ "return",
2482
+ "short",
2483
+ "signed",
2484
+ "sizeof",
2485
+ "static",
2486
+ "static_assert",
2487
+ "static_cast",
2488
+ "struct",
2489
+ "switch",
2490
+ "synchronized",
2491
+ "template",
2492
+ "this",
2493
+ "thread_local",
2494
+ "throw",
2495
+ "true",
2496
+ "try",
2497
+ "typedef",
2498
+ "typeid",
2499
+ "typename",
2500
+ "union",
2501
+ "unsigned",
2502
+ "using",
2503
+ "virtual",
2504
+ "void",
2505
+ "volatile",
2506
+ "wchar_t",
2507
+ "while",
2508
+ "xor",
2509
+ "xor_eq",
2510
+ }
2511
+ )
2512
+ .union(
2513
+ # C#, see: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/
2514
+ {
2515
+ "abstract",
2516
+ "as",
2517
+ "base",
2518
+ "bool",
2519
+ "break",
2520
+ "byte",
2521
+ "case",
2522
+ "catch",
2523
+ "char",
2524
+ "checked",
2525
+ "class",
2526
+ "const",
2527
+ "continue",
2528
+ "decimal",
2529
+ "default",
2530
+ "delegate",
2531
+ "do",
2532
+ "double",
2533
+ "else",
2534
+ "enum",
2535
+ "event",
2536
+ "explicit",
2537
+ "extern",
2538
+ "false",
2539
+ "finally",
2540
+ "fixed",
2541
+ "float",
2542
+ "for",
2543
+ "foreach",
2544
+ "goto",
2545
+ "if",
2546
+ "implicit",
2547
+ "in",
2548
+ "int",
2549
+ "interface",
2550
+ "internal",
2551
+ "is",
2552
+ "lock",
2553
+ "long",
2554
+ "namespace",
2555
+ "new",
2556
+ "null",
2557
+ "object",
2558
+ "operator",
2559
+ "out",
2560
+ "override",
2561
+ "params",
2562
+ "private",
2563
+ "protected",
2564
+ "public",
2565
+ "readonly",
2566
+ "ref",
2567
+ "return",
2568
+ "sbyte",
2569
+ "sealed",
2570
+ "short",
2571
+ "sizeof",
2572
+ "stackalloc",
2573
+ "static",
2574
+ "string",
2575
+ "struct",
2576
+ "switch",
2577
+ "this",
2578
+ "throw",
2579
+ "true",
2580
+ "try",
2581
+ "typeof",
2582
+ "uint",
2583
+ "ulong",
2584
+ "unchecked",
2585
+ "unsafe",
2586
+ "ushort",
2587
+ "using",
2588
+ "virtual",
2589
+ "void",
2590
+ "volatile",
2591
+ "while",
2592
+ }
2593
+ )
2594
+ .union(
2595
+ # D, see: https://dlang.org/spec/lex.html#keywords
2596
+ #
2597
+ # We exclude ``version`` from the keywords as its usage in
2598
+ # the meta-model predates the generation of the D SDK, so it has been
2599
+ # missed, unfortunately.
2600
+ {
2601
+ "abstract",
2602
+ "alias",
2603
+ "align",
2604
+ "asm",
2605
+ "assert",
2606
+ "auto",
2607
+ "body",
2608
+ "bool",
2609
+ "break",
2610
+ "byte",
2611
+ "case",
2612
+ "cast",
2613
+ "catch",
2614
+ "cdouble",
2615
+ "cent",
2616
+ "cfloat",
2617
+ "char",
2618
+ "class",
2619
+ "const",
2620
+ "continue",
2621
+ "creal",
2622
+ "dchar",
2623
+ "debug",
2624
+ "default",
2625
+ "delegate",
2626
+ "delete",
2627
+ "deprecated",
2628
+ "do",
2629
+ "double",
2630
+ "else",
2631
+ "enum",
2632
+ "export",
2633
+ "extern",
2634
+ "false",
2635
+ "final",
2636
+ "finally",
2637
+ "float",
2638
+ "for",
2639
+ "foreach",
2640
+ "foreach_reverse",
2641
+ "function",
2642
+ "goto",
2643
+ "idouble",
2644
+ "if",
2645
+ "ifloat",
2646
+ "immutable",
2647
+ "import",
2648
+ "in",
2649
+ "inout",
2650
+ "int",
2651
+ "interface",
2652
+ "invariant",
2653
+ "ireal",
2654
+ "is",
2655
+ "lazy",
2656
+ "long",
2657
+ "macro",
2658
+ "mixin",
2659
+ "module",
2660
+ "new",
2661
+ "nothrow",
2662
+ "null",
2663
+ "out",
2664
+ "override",
2665
+ "package",
2666
+ "pragma",
2667
+ "private",
2668
+ "protected",
2669
+ "public",
2670
+ "pure",
2671
+ "real",
2672
+ "ref",
2673
+ "return",
2674
+ "scope",
2675
+ "shared",
2676
+ "short",
2677
+ "static",
2678
+ "struct",
2679
+ "super",
2680
+ "switch",
2681
+ "synchronized",
2682
+ "template",
2683
+ "this",
2684
+ "throw",
2685
+ "true",
2686
+ "try",
2687
+ "typeid",
2688
+ "typeof",
2689
+ "ubyte",
2690
+ "ucent",
2691
+ "uint",
2692
+ "ulong",
2693
+ "union",
2694
+ "unittest",
2695
+ "ushort",
2696
+ "void",
2697
+ "wchar",
2698
+ "while",
2699
+ "with",
2700
+ }
2701
+ )
2702
+ .union(
2703
+ # Eiffel, see: https://www.eiffel.org/doc/eiffel/Eiffel_programming_language_reserved_words
2704
+ {
2705
+ "across",
2706
+ "agent",
2707
+ "alias",
2708
+ "all",
2709
+ "and",
2710
+ "as",
2711
+ "assign",
2712
+ "attribute",
2713
+ "check",
2714
+ "class",
2715
+ "convert",
2716
+ "create",
2717
+ "current",
2718
+ "debug",
2719
+ "deferred",
2720
+ "do",
2721
+ "else",
2722
+ "elseif",
2723
+ "end",
2724
+ "ensure",
2725
+ "expanded",
2726
+ "export",
2727
+ "external",
2728
+ "false",
2729
+ "feature",
2730
+ "from",
2731
+ "frozen",
2732
+ "if",
2733
+ "implies",
2734
+ "inherit",
2735
+ "inspect",
2736
+ "invariant",
2737
+ "like",
2738
+ "local",
2739
+ "loop",
2740
+ "not",
2741
+ "note",
2742
+ "obsolete",
2743
+ "old",
2744
+ "once",
2745
+ "only",
2746
+ "or",
2747
+ "precursor",
2748
+ "redefine",
2749
+ "rename",
2750
+ "require",
2751
+ "rescue",
2752
+ # NOTE (mristin, 2024-06-19):
2753
+ # We exclude the keyword ``result`` from the checks as the AAS server
2754
+ # API at version 3.0 already uses it for one of the object properties.
2755
+ # We have to work around it in the code generator for Eiffel SDK.
2756
+ # "result",
2757
+ "retry",
2758
+ "select",
2759
+ "separate",
2760
+ "then",
2761
+ "true",
2762
+ "tuple",
2763
+ "undefine",
2764
+ "until",
2765
+ "variant",
2766
+ "void",
2767
+ "when",
2768
+ "xor",
2769
+ }
2770
+ )
2771
+ .union(
2772
+ # Elixir, see: https://hexdocs.pm/elixir/1.12.3/syntax-reference.html#reserved-words
2773
+ {
2774
+ "after",
2775
+ "and",
2776
+ "catch",
2777
+ "do",
2778
+ "else",
2779
+ "end",
2780
+ "false",
2781
+ "fn",
2782
+ "in",
2783
+ "nil",
2784
+ "not",
2785
+ "or",
2786
+ "rescue",
2787
+ "true",
2788
+ "when",
2789
+ }
2790
+ )
2791
+ .union(
2792
+ # Erlang, see: https://www.erlang.org/doc/reference_manual/introduction.html#reserved-words
2793
+ {
2794
+ "after",
2795
+ "and",
2796
+ "andalso",
2797
+ "band",
2798
+ "begin",
2799
+ "bnot",
2800
+ "bor",
2801
+ "bsl",
2802
+ "bsr",
2803
+ "bxor",
2804
+ "case",
2805
+ "catch",
2806
+ "cond",
2807
+ "div",
2808
+ "end",
2809
+ "fun",
2810
+ "if",
2811
+ "let",
2812
+ "maybe",
2813
+ "not",
2814
+ "of",
2815
+ "or",
2816
+ "orelse",
2817
+ "receive",
2818
+ "rem",
2819
+ "try",
2820
+ "when",
2821
+ "xor",
2822
+ }
2823
+ )
2824
+ .union(
2825
+ # Go, see: https://go.dev/ref/spec#Keywords.
2826
+ #
2827
+ # We exclude ``type`` and ``range`` from the keywords as its usage in
2828
+ # the meta-model predates the generation of the Go SDK, so it has been
2829
+ # missed, unfortunately.
2830
+ {
2831
+ "break",
2832
+ "case",
2833
+ "chan",
2834
+ "const",
2835
+ "continue",
2836
+ "default",
2837
+ "defer",
2838
+ "else",
2839
+ "fallthrough",
2840
+ "for",
2841
+ "func",
2842
+ "go",
2843
+ "goto",
2844
+ "if",
2845
+ "import",
2846
+ "interface",
2847
+ "map",
2848
+ "package",
2849
+ "return",
2850
+ "select",
2851
+ "struct",
2852
+ "switch",
2853
+ "var",
2854
+ }
2855
+ )
2856
+ .union(
2857
+ # Java, see: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html
2858
+ {
2859
+ "abstract",
2860
+ "assert",
2861
+ "boolean",
2862
+ "break",
2863
+ "byte",
2864
+ "case",
2865
+ "catch",
2866
+ "char",
2867
+ "class",
2868
+ "const",
2869
+ "continue",
2870
+ "default",
2871
+ "do",
2872
+ "double",
2873
+ "else",
2874
+ "enum",
2875
+ "extends",
2876
+ "final",
2877
+ "finally",
2878
+ "float",
2879
+ "for",
2880
+ "goto",
2881
+ "if",
2882
+ "implements",
2883
+ "import",
2884
+ "instanceof",
2885
+ "int",
2886
+ "interface",
2887
+ "long",
2888
+ "native",
2889
+ "new",
2890
+ "package",
2891
+ "private",
2892
+ "protected",
2893
+ "public",
2894
+ "return",
2895
+ "short",
2896
+ "static",
2897
+ "strictfp",
2898
+ "super",
2899
+ "switch",
2900
+ "synchronized",
2901
+ "this",
2902
+ "throw",
2903
+ "throws",
2904
+ "transient",
2905
+ "try",
2906
+ "void",
2907
+ "volatile",
2908
+ "while",
2909
+ }
2910
+ )
2911
+ .union(
2912
+ # Python, see: https://docs.python.org/3/reference/lexical_analysis.html#keywords
2913
+ {
2914
+ "and",
2915
+ "as",
2916
+ "assert",
2917
+ "async",
2918
+ "await",
2919
+ "break",
2920
+ "class",
2921
+ "continue",
2922
+ "def",
2923
+ "del",
2924
+ "elif",
2925
+ "else",
2926
+ "except",
2927
+ "false",
2928
+ "finally",
2929
+ "for",
2930
+ "from",
2931
+ "global",
2932
+ "if",
2933
+ "import",
2934
+ "in",
2935
+ "is",
2936
+ "lambda",
2937
+ "none",
2938
+ "nonlocal",
2939
+ "not",
2940
+ "or",
2941
+ "pass",
2942
+ "raise",
2943
+ "return",
2944
+ "true",
2945
+ "try",
2946
+ "while",
2947
+ "with",
2948
+ "yield",
2949
+ }
2950
+ )
2951
+ .union(
2952
+ # Rust, see: https://doc.rust-lang.org/reference/keywords.html
2953
+ #
2954
+ # We exclude ``type`` from the keywords as its usage in the meta-model
2955
+ # predates the generation of the Rust SDK, so it has been missed,
2956
+ # unfortunately.
2957
+ {
2958
+ "abstract",
2959
+ "as",
2960
+ "async",
2961
+ "await",
2962
+ "become",
2963
+ "box",
2964
+ "break",
2965
+ "const",
2966
+ "continue",
2967
+ "crate",
2968
+ "do",
2969
+ "dyn",
2970
+ "else",
2971
+ "enum",
2972
+ "extern",
2973
+ "false",
2974
+ "final",
2975
+ "fn",
2976
+ "for",
2977
+ "if",
2978
+ "impl",
2979
+ "in",
2980
+ "let",
2981
+ "loop",
2982
+ "macro",
2983
+ "match",
2984
+ "mod",
2985
+ "move",
2986
+ "mut",
2987
+ "override",
2988
+ "priv",
2989
+ "pub",
2990
+ "ref",
2991
+ "return",
2992
+ "self",
2993
+ "static",
2994
+ "struct",
2995
+ "super",
2996
+ "trait",
2997
+ "true",
2998
+ "try",
2999
+ "typeof",
3000
+ "union",
3001
+ "unsafe",
3002
+ "unsized",
3003
+ "use",
3004
+ "virtual",
3005
+ "where",
3006
+ "while",
3007
+ "yield",
3008
+ }
3009
+ )
3010
+ .union(
3011
+ # TypeScript, see: https://github.com/microsoft/TypeScript/issues/2536#issuecomment-87194347
3012
+ #
3013
+ # We exclude ``type`` and ``symbol`` from the keywords as its usage in
3014
+ # the meta-model predates the generation of the TypeScript SDK, so it has
3015
+ # been missed, unfortunately.
3016
+ {
3017
+ "any",
3018
+ "as",
3019
+ "boolean",
3020
+ "break",
3021
+ "case",
3022
+ "catch",
3023
+ "class",
3024
+ "const",
3025
+ "constructor",
3026
+ "continue",
3027
+ "debugger",
3028
+ "declare",
3029
+ "default",
3030
+ "delete",
3031
+ "do",
3032
+ "else",
3033
+ "enum",
3034
+ "export",
3035
+ "extends",
3036
+ "false",
3037
+ "finally",
3038
+ "for",
3039
+ "from",
3040
+ "function",
3041
+ "get",
3042
+ "if",
3043
+ "implements",
3044
+ "import",
3045
+ "in",
3046
+ "instanceof",
3047
+ "interface",
3048
+ "let",
3049
+ "module",
3050
+ "new",
3051
+ "null",
3052
+ "number",
3053
+ "of",
3054
+ "package",
3055
+ "private",
3056
+ "protected",
3057
+ "public",
3058
+ "require",
3059
+ "return",
3060
+ "set",
3061
+ "static",
3062
+ "string",
3063
+ "super",
3064
+ "switch",
3065
+ "this",
3066
+ "throw",
3067
+ "true",
3068
+ "try",
3069
+ "typeof",
3070
+ "var",
3071
+ "void",
3072
+ "while",
3073
+ "with",
3074
+ "yield",
3075
+ }
3076
+ )
3077
+ )
3078
+
3079
+ for keyword in keywords_in_many_implementations:
3080
+ assert keyword == keyword.lower(), f"{keyword=}, {keyword.lower()=}"
3081
+
3082
+ # noinspection SpellCheckingInspection
3083
+ reserved_type_names = keywords_in_many_implementations.union(
3084
+ # Types used in aas-core implementations
3085
+ {
3086
+ "aas",
3087
+ "accept",
3088
+ "context",
3089
+ "class",
3090
+ "error",
3091
+ "errors",
3092
+ "iclass",
3093
+ "itransformer_with_context",
3094
+ "ivisitor",
3095
+ "ivisitor_with_context",
3096
+ "jsonization",
3097
+ "path",
3098
+ "stringification",
3099
+ "transform",
3100
+ "transformer",
3101
+ "transformer_with_context",
3102
+ "verification",
3103
+ "visit",
3104
+ "visitation",
3105
+ "visitor",
3106
+ "visitor_with_context",
3107
+ "match",
3108
+ "constants",
3109
+ "model_type",
3110
+ "enhancement",
3111
+ "enhanced",
3112
+ "descent",
3113
+ "iterator",
3114
+ "serialization_error",
3115
+ "deserialization_error",
3116
+ "verification_error",
3117
+ }
3118
+ ).union(
3119
+ # Utility types in Typescript,
3120
+ # see: https://www.typescriptlang.org/docs/handbook/utility-types.html
3121
+ {
3122
+ "awaited",
3123
+ "partial",
3124
+ "required",
3125
+ "readonly",
3126
+ "record",
3127
+ "pick",
3128
+ "omit",
3129
+ "exclude",
3130
+ "extract",
3131
+ "non_nullable",
3132
+ "parameters",
3133
+ "constructor_parameters",
3134
+ "return_type",
3135
+ "instance_type",
3136
+ "this_parameter_type",
3137
+ "omit_this_parameter",
3138
+ "this_type",
3139
+ "uppercase",
3140
+ "lowercase",
3141
+ "capitalize",
3142
+ "uncapitalize",
3143
+ }
3144
+ )
3145
+
3146
+ # NOTE (mristin, 2023-06-30):
3147
+ # We check against the lower-case to report even if the case is different, so
3148
+ # the type names are lower-cased in this set as well.
3149
+ for type_name in reserved_type_names:
3150
+ assert type_name == type_name.lower(), f"{type_name=}, {type_name.lower()=}"
3151
+
3152
+ reserved_member_names = keywords_in_many_implementations.union(
3153
+ {
3154
+ "descend",
3155
+ "descend_once",
3156
+ "accept",
3157
+ "transform",
3158
+ "type_name",
3159
+ "property_name",
3160
+ "match",
3161
+ "model_type",
3162
+ "get_model_type",
3163
+ "set_model_type",
3164
+ "set_enhancement",
3165
+ "get_enhancement",
3166
+ "enhancement",
3167
+ }
3168
+ )
3169
+
3170
+ for our_type in symbol_table.our_types:
3171
+ if our_type.name.startswith("I_"):
3172
+ errors.append(
3173
+ Error(
3174
+ our_type.node,
3175
+ f"The prefix ``I_`` in the name of the type is reserved "
3176
+ f"for the code generation: {our_type.name!r}",
3177
+ )
3178
+ )
3179
+
3180
+ if our_type.name.startswith("Must_"):
3181
+ errors.append(
3182
+ Error(
3183
+ our_type.node,
3184
+ f"The prefix ``Must_`` in the name of the type is reserved "
3185
+ f"for the code generation: {our_type.name!r}",
3186
+ )
3187
+ )
3188
+
3189
+ if our_type.name.lower() in reserved_type_names:
3190
+ errors.append(
3191
+ Error(
3192
+ our_type.node,
3193
+ f"The name of the type is reserved "
3194
+ f"for the code generation: {our_type.name!r}",
3195
+ )
3196
+ )
3197
+
3198
+ if isinstance(our_type, Class):
3199
+ for method in our_type.methods:
3200
+ if method.name.lower() in reserved_member_names:
3201
+ errors.append(
3202
+ Error(
3203
+ method.node,
3204
+ f"The name of the method is reserved "
3205
+ f"for the code generation: {method.name!r}",
3206
+ )
3207
+ )
3208
+
3209
+ # noinspection SpellCheckingInspection
3210
+ if method.name.lower().startswith("over") and (
3211
+ method.name.lower().endswith("or_empty")
3212
+ or method.name.lower().endswith("orempty")
3213
+ ):
3214
+ errors.append(
3215
+ Error(
3216
+ method.node,
3217
+ f"The name of the method is reserved "
3218
+ f"for the code generation of "
3219
+ f'enumerable "Over_X_or_Empty" getters: {method.name!r}',
3220
+ )
3221
+ )
3222
+
3223
+ if method.name.lower().startswith("mutable"):
3224
+ errors.append(
3225
+ Error(
3226
+ method.node,
3227
+ f"The prefix 'mutable' in the name of the method "
3228
+ f"is reserved for the code generation in languages "
3229
+ f"such as C++ which distinguish between "
3230
+ f"mutating and const getters: {method.name!r}",
3231
+ )
3232
+ )
3233
+
3234
+ for prop in our_type.properties:
3235
+ if prop.name.lower() in reserved_member_names:
3236
+ errors.append(
3237
+ Error(
3238
+ prop.node,
3239
+ f"The name of the property is reserved "
3240
+ f"for the code generation: {prop.name!r}",
3241
+ )
3242
+ )
3243
+
3244
+ if prop.name.lower().startswith("mutable"):
3245
+ errors.append(
3246
+ Error(
3247
+ prop.node,
3248
+ f"The prefix 'mutable' in the name of the property is "
3249
+ f"reserved for the code generation in languages "
3250
+ f"such as C++ which distinguish between "
3251
+ f"mutating and const getters: {prop.name!r}",
3252
+ )
3253
+ )
3254
+
3255
+ for constant in symbol_table.constants:
3256
+ constant_name_lower = constant.name.lower()
3257
+ if (
3258
+ constant_name_lower in reserved_member_names
3259
+ or constant_name_lower in reserved_type_names
3260
+ ):
3261
+ errors.append(
3262
+ Error(
3263
+ constant.node,
3264
+ f"The name of the constant is reserved "
3265
+ f"for the code generation: {constant.name!r}",
3266
+ )
3267
+ )
3268
+
3269
+ for func in symbol_table.verification_functions:
3270
+ func_name_lower = func.name.lower()
3271
+ if (
3272
+ func_name_lower in reserved_member_names
3273
+ or func_name_lower in reserved_type_names
3274
+ ):
3275
+ errors.append(
3276
+ Error(
3277
+ func.node,
3278
+ f"The name of the verification function is reserved "
3279
+ f"for the code generation: {func.name!r}",
3280
+ )
3281
+ )
3282
+
3283
+ # endregion
3284
+
3285
+ # region Check that there are no duplicate type names
3286
+
3287
+ observed_type_names = dict() # type: MutableMapping[Identifier, OurType]
3288
+ for our_type in symbol_table.our_types:
3289
+ another_our_type = observed_type_names.get(our_type.name, None)
3290
+ if another_our_type is None:
3291
+ observed_type_names[our_type.name] = our_type
3292
+ else:
3293
+ errors.append(
3294
+ Error(
3295
+ our_type.node,
3296
+ f"Our type with the name {our_type.name!r} conflicts with "
3297
+ f"other type with the same name.",
3298
+ )
3299
+ )
3300
+
3301
+ # endregion
3302
+
3303
+ # region Check that there are no duplicate names of the constants
3304
+
3305
+ observed_constant_names = dict() # type: MutableMapping[Identifier, Constant]
3306
+ for constant in symbol_table.constants:
3307
+ another_constant = observed_constant_names.get(constant.name, None)
3308
+ if another_constant is None:
3309
+ observed_constant_names[constant.name] = constant
3310
+ else:
3311
+ errors.append(
3312
+ Error(
3313
+ constant.node,
3314
+ f"The constant with the name {constant.name!r} conflicts with "
3315
+ f"another constant with the same name.",
3316
+ )
3317
+ )
3318
+
3319
+ # endregion
3320
+
3321
+ # region Check that there are no duplicate names of the verification functions
3322
+
3323
+ observed_verification_func_names = (
3324
+ dict()
3325
+ ) # type: MutableMapping[Identifier, FunctionUnion]
3326
+
3327
+ for func in symbol_table.verification_functions:
3328
+ another_func = observed_verification_func_names.get(func.name, None)
3329
+ if another_func is None:
3330
+ observed_verification_func_names[func.name] = func
3331
+ else:
3332
+ errors.append(
3333
+ Error(
3334
+ func.node,
3335
+ f"The verification function with the name {func.name!r} conflicts "
3336
+ f"with another verification function with the same name.",
3337
+ )
3338
+ )
3339
+
3340
+ # endregion
3341
+
3342
+ if len(errors) > 0:
3343
+ return None, errors
3344
+
3345
+ # region Check that imported symbols are not re-assigned in an understood method
3346
+
3347
+ for understood_method in itertools.chain(
3348
+ (
3349
+ method
3350
+ for method in symbol_table.verification_functions
3351
+ if isinstance(method, UnderstoodMethod)
3352
+ ),
3353
+ (
3354
+ method
3355
+ for our_type in symbol_table.our_types
3356
+ if isinstance(our_type, Class)
3357
+ for method in our_type.methods
3358
+ if isinstance(method, UnderstoodMethod)
3359
+ ),
3360
+ ):
3361
+ for stmt in understood_method.body:
3362
+ if (
3363
+ isinstance(stmt, tree.Assignment)
3364
+ and isinstance(stmt.target, tree.Name)
3365
+ and stmt.target.identifier == "match"
3366
+ ):
3367
+ errors.append(
3368
+ Error(
3369
+ stmt.original_node,
3370
+ "The name ``match`` is reserved "
3371
+ "for the function ``match`` "
3372
+ "imported from the ``re`` module of "
3373
+ "the standard Python library",
3374
+ )
3375
+ )
3376
+
3377
+ # endregion
3378
+
3379
+ # region Check that no class methods are used in verification
3380
+
3381
+ for our_type in symbol_table.our_types:
3382
+ if not isinstance(our_type, Class):
3383
+ continue
3384
+
3385
+ for method in our_type.methods:
3386
+ if method.verification:
3387
+ errors.append(
3388
+ Error(
3389
+ method.node,
3390
+ f"Unexpected verification function "
3391
+ f"in a class {our_type.name!r}: {method.name!r}",
3392
+ )
3393
+ )
3394
+
3395
+ # endregion
3396
+
3397
+ # region Check that only instance methods are non-mutating
3398
+
3399
+ for verification_func in symbol_table.verification_functions:
3400
+ if verification_func.non_mutating:
3401
+ errors.append(
3402
+ Error(
3403
+ verification_func.node,
3404
+ f"Functions can not be non-mutating: {verification_func.name!r}",
3405
+ )
3406
+ )
3407
+
3408
+ # endregion
3409
+
3410
+ # region Check dangling inheritances
3411
+
3412
+ for our_type in symbol_table.our_types:
3413
+ if not isinstance(our_type, Class):
3414
+ continue
3415
+
3416
+ for inheritance in our_type.inheritances:
3417
+ # NOTE (mristin, 2021-12-22):
3418
+ # Inheritance from primitive types allows us to constrain a primitive type.
3419
+ if inheritance in PRIMITIVE_TYPES:
3420
+ continue
3421
+
3422
+ parent_type = symbol_table.find_our_type(name=inheritance)
3423
+
3424
+ if parent_type is None:
3425
+ errors.append(
3426
+ Error(
3427
+ our_type.node,
3428
+ f"A parent of the class {our_type.name!r} "
3429
+ f"is dangling: {inheritance!r}",
3430
+ )
3431
+ )
3432
+
3433
+ elif isinstance(parent_type, Class):
3434
+ # A class can inherit from a class.
3435
+ pass
3436
+ else:
3437
+ errors.append(
3438
+ Error(
3439
+ our_type.node,
3440
+ f"Expected the class {our_type.name!r} to inherit "
3441
+ f"from another class, "
3442
+ f"but it inherits from our type {parent_type.name!r} which is "
3443
+ f"a {parent_type.__class__.__name__!r}",
3444
+ )
3445
+ )
3446
+
3447
+ if len(errors) > 0:
3448
+ return None, errors
3449
+
3450
+ # endregion
3451
+
3452
+ # region Check dangling subsets in constant sets
3453
+
3454
+ for constant in symbol_table.constants:
3455
+ if not isinstance(constant, ConstantSet):
3456
+ continue
3457
+
3458
+ for subset_name in constant.subsets:
3459
+ subset = symbol_table.find_constant(name=subset_name)
3460
+
3461
+ if subset is None:
3462
+ errors.append(
3463
+ Error(
3464
+ constant.node,
3465
+ f"The subset {subset_name!r} "
3466
+ f"of the constant set {constant.name!r} is dangling",
3467
+ )
3468
+ )
3469
+ elif not isinstance(subset, ConstantSet):
3470
+ errors.append(
3471
+ Error(
3472
+ constant.node,
3473
+ f"The subset {subset_name!r} "
3474
+ f"of the constant set {constant.name!r} is not a constant set, "
3475
+ f"but: {constant.__class__.__name__}",
3476
+ )
3477
+ )
3478
+ else:
3479
+ pass
3480
+
3481
+ # endregion
3482
+
3483
+ # region Check type annotations
3484
+
3485
+ expected_subscripted_types = GENERIC_TYPES
3486
+
3487
+ # NOTE (mristin, 2021-11-19):
3488
+ # If you expect type qualifiers such as ``Final``, make a copy of
3489
+ # the ``GENERIC_TYPES`` and add them to the copy.
3490
+
3491
+ def verify_no_dangling_references_in_type_annotation(
3492
+ type_annotation: TypeAnnotation,
3493
+ ) -> Optional[Error]:
3494
+ """
3495
+ Check that the type annotation contains no dangling references.
3496
+
3497
+ :return: error message, if any
3498
+ """
3499
+ if isinstance(type_annotation, AtomicTypeAnnotation):
3500
+ if type_annotation.identifier in PRIMITIVE_TYPES:
3501
+ return None
3502
+
3503
+ if type_annotation.identifier in expected_subscripted_types:
3504
+ return Error(
3505
+ type_annotation.node,
3506
+ f"The type annotation is expected with subscript(s), "
3507
+ f"but got none: {type_annotation.identifier}",
3508
+ )
3509
+
3510
+ if symbol_table.find_our_type(type_annotation.identifier) is not None:
3511
+ return None
3512
+
3513
+ return Error(
3514
+ type_annotation.node,
3515
+ f"Our type could not be found "
3516
+ f"in the symbol table: {type_annotation.identifier}",
3517
+ )
3518
+
3519
+ elif isinstance(type_annotation, SubscriptedTypeAnnotation):
3520
+ if type_annotation.identifier not in expected_subscripted_types:
3521
+ return Error(
3522
+ type_annotation.node,
3523
+ f"Unexpected subscripted type: {type_annotation.identifier}",
3524
+ )
3525
+
3526
+ for subscript in type_annotation.subscripts:
3527
+ error_in_subscript = verify_no_dangling_references_in_type_annotation(
3528
+ type_annotation=subscript
3529
+ )
3530
+ if error_in_subscript is not None:
3531
+ return error_in_subscript
3532
+
3533
+ return None
3534
+
3535
+ elif isinstance(type_annotation, SelfTypeAnnotation):
3536
+ return None
3537
+
3538
+ else:
3539
+ assert_never(type_annotation)
3540
+
3541
+ for our_type in symbol_table.our_types:
3542
+ if not isinstance(our_type, Class):
3543
+ continue
3544
+
3545
+ for prop in our_type.properties:
3546
+ error = verify_no_dangling_references_in_type_annotation(
3547
+ type_annotation=prop.type_annotation
3548
+ )
3549
+
3550
+ if error is not None:
3551
+ errors.append(error)
3552
+ else:
3553
+ if isinstance(prop.type_annotation, SubscriptedTypeAnnotation):
3554
+ error = _verify_arity_of_type_annotation_subscript(
3555
+ prop.type_annotation
3556
+ )
3557
+
3558
+ if error is not None:
3559
+ errors.append(error)
3560
+
3561
+ for method in our_type.methods:
3562
+ for arg in method.arguments:
3563
+ error = verify_no_dangling_references_in_type_annotation(
3564
+ type_annotation=arg.type_annotation
3565
+ )
3566
+
3567
+ if error is not None:
3568
+ errors.append(error)
3569
+ else:
3570
+ if isinstance(arg.type_annotation, SubscriptedTypeAnnotation):
3571
+ error = _verify_arity_of_type_annotation_subscript(
3572
+ arg.type_annotation
3573
+ )
3574
+
3575
+ if error is not None:
3576
+ errors.append(error)
3577
+
3578
+ if method.returns is not None:
3579
+ error = verify_no_dangling_references_in_type_annotation(
3580
+ type_annotation=method.returns
3581
+ )
3582
+ if error is not None:
3583
+ errors.append(error)
3584
+ else:
3585
+ if isinstance(method.returns, SubscriptedTypeAnnotation):
3586
+ error = _verify_arity_of_type_annotation_subscript(
3587
+ method.returns
3588
+ )
3589
+
3590
+ if error is not None:
3591
+ errors.append(error)
3592
+
3593
+ for constant in symbol_table.constants:
3594
+ if isinstance(constant, ConstantPrimitive):
3595
+ pass
3596
+
3597
+ elif isinstance(constant, ConstantSet):
3598
+ error = verify_no_dangling_references_in_type_annotation(
3599
+ type_annotation=constant.items_type_annotation
3600
+ )
3601
+
3602
+ if error is not None:
3603
+ errors.append(error)
3604
+
3605
+ else:
3606
+ assert_never(constant)
3607
+
3608
+ if len(errors) > 0:
3609
+ return None, errors
3610
+
3611
+ # endregion
3612
+
3613
+ if len(errors) > 0:
3614
+ return None, errors
3615
+
3616
+ return SymbolTable(symbol_table), None
3617
+
3618
+
3619
+ Symbol = Union[
3620
+ AbstractClass,
3621
+ ConcreteClass,
3622
+ Enumeration,
3623
+ ConstantPrimitive,
3624
+ ConstantSet,
3625
+ UnderstoodMethod,
3626
+ ImplementationSpecificMethod,
3627
+ ]
3628
+
3629
+
3630
+ # fmt: off
3631
+ @ensure(
3632
+ lambda result: not (result is not None) or (len(result) >= 1),
3633
+ "Either null errors or at least one error"
3634
+ )
3635
+ # fmt: on
3636
+ def _verify_duplicate_names(
3637
+ symbols: Iterable[Symbol],
3638
+ ) -> Optional[List[Error]]:
3639
+ """Determine the duplicate names in the given sequence of nameable instances."""
3640
+ name_set = set() # type: Set[Identifier]
3641
+ errors = [] # type: List[Error]
3642
+ for symbol in symbols:
3643
+ if symbol.name in name_set:
3644
+ errors.append(Error(symbol.node, f"Duplicate for {symbol.name!r}"))
3645
+ else:
3646
+ name_set.add(symbol.name)
3647
+
3648
+ if len(errors) > 0:
3649
+ return errors
3650
+
3651
+ return None
3652
+
3653
+
3654
+ # noinspection PyTypeChecker,PyUnresolvedReferences
3655
+ @require(lambda atok: isinstance(atok.tree, ast.Module))
3656
+ @ensure(lambda result: (result[0] is None) ^ (result[1] is None))
3657
+ def _atok_to_symbol_table(
3658
+ atok: asttokens.ASTTokens,
3659
+ ) -> Tuple[Optional[SymbolTable], Optional[Error]]:
3660
+ our_types = [] # type: List[OurType]
3661
+ underlying_errors = [] # type: List[Error]
3662
+
3663
+ description = None # type: Optional[Description]
3664
+ version = None # type: Optional[str]
3665
+ xml_namespace = None # type: Optional[Stripped]
3666
+
3667
+ verification_functions = [] # type: List[FunctionUnion]
3668
+ constants = [] # type: List[ConstantUnion]
3669
+
3670
+ # region Parse
3671
+
3672
+ assert atok.tree is not None
3673
+
3674
+ for node in atok.tree.body:
3675
+ # NOTE (mristin, 2021-12-27):
3676
+ # Pass statement makes no sense in our multi-language setting.
3677
+ if isinstance(node, ast.Pass):
3678
+ continue
3679
+
3680
+ # NOTE (mristin, 2022-07-10):
3681
+ # We currently decided to ignore assertions though we leave them in
3682
+ # the meta-model as documentation
3683
+ if isinstance(node, ast.Assert):
3684
+ continue
3685
+
3686
+ # noinspection PyUnusedLocal
3687
+ matched = False
3688
+
3689
+ if isinstance(node, ast.ClassDef):
3690
+ matched = True
3691
+
3692
+ our_type, our_type_error = _classdef_to_our_type(node=node, atok=atok)
3693
+ if our_type_error:
3694
+ underlying_errors.append(
3695
+ Error(
3696
+ node,
3697
+ f"Failed to parse the class definition: {node.name}",
3698
+ [our_type_error],
3699
+ )
3700
+ )
3701
+ else:
3702
+ assert our_type is not None
3703
+ our_types.append(our_type)
3704
+
3705
+ elif (
3706
+ isinstance(node, ast.Expr)
3707
+ and isinstance(node.value, ast.Constant)
3708
+ and isinstance(node.value.value, str)
3709
+ ):
3710
+ matched = True
3711
+
3712
+ # The first string literal is assumed to be the docstring of the meta-model.
3713
+ description, description_error = _ast_constant_string_to_description(
3714
+ constant=node.value
3715
+ )
3716
+
3717
+ if description_error is not None:
3718
+ assert description is None
3719
+ underlying_errors.append(description_error)
3720
+ continue
3721
+
3722
+ elif isinstance(node, ast.FunctionDef):
3723
+ matched = True
3724
+
3725
+ method, error = _function_def_to_method(
3726
+ node=node, expect_self=False, atok=atok
3727
+ )
3728
+
3729
+ if error is not None:
3730
+ underlying_errors.append(error)
3731
+ continue
3732
+
3733
+ assert method is not None
3734
+
3735
+ if not method.verification:
3736
+ underlying_errors.append(
3737
+ Error(
3738
+ node,
3739
+ f"We do not know how to interpret a non-verification function "
3740
+ f"in the meta-model: {method.name!r}",
3741
+ )
3742
+ )
3743
+
3744
+ assert isinstance(method, (UnderstoodMethod, ImplementationSpecificMethod))
3745
+ verification_functions.append(method)
3746
+
3747
+ elif isinstance(node, ast.ImportFrom):
3748
+ matched = True
3749
+
3750
+ # Ignore import statements
3751
+ pass
3752
+
3753
+ elif isinstance(node, ast.Assign):
3754
+ if len(node.targets) == 1:
3755
+ if (
3756
+ isinstance(node.targets[0], ast.Name)
3757
+ and isinstance(node.value, ast.Constant)
3758
+ and isinstance(node.value.value, str)
3759
+ ):
3760
+ matched = True
3761
+
3762
+ if node.targets[0].id == "__version__":
3763
+ version = node.value.value
3764
+ elif node.targets[0].id == "__xml_namespace__":
3765
+ if not is_stripped(node.value.value):
3766
+ underlying_errors.append(
3767
+ Error(
3768
+ node.value,
3769
+ f"Expected the XML namespace to have no leading "
3770
+ f"or trailing whitespace: {node.value.value!r}",
3771
+ )
3772
+ )
3773
+ continue
3774
+
3775
+ if node.value.value.endswith("/"):
3776
+ underlying_errors.append(
3777
+ Error(
3778
+ node.value,
3779
+ f"Expected the XML namespace to have no trailing "
3780
+ f"slash ('/'), but got: {node.value.value!r}",
3781
+ )
3782
+ )
3783
+ continue
3784
+
3785
+ contains_unexpected_char = False
3786
+ for unexpected_char, unexpected_char_name in [
3787
+ ('"', "double-quote"),
3788
+ ("'", "single-quote"),
3789
+ ]:
3790
+ if unexpected_char in node.value.value:
3791
+ underlying_errors.append(
3792
+ Error(
3793
+ node.value,
3794
+ f"Expected the XML namespace to have no "
3795
+ f"{unexpected_char_name} ({unexpected_char!r}),"
3796
+ f"but got: {node.value.value!r}",
3797
+ )
3798
+ )
3799
+ contains_unexpected_char = True
3800
+
3801
+ if contains_unexpected_char:
3802
+ continue
3803
+
3804
+ xml_namespace = Stripped(node.value.value)
3805
+ else:
3806
+ underlying_errors.append(
3807
+ Error(
3808
+ node,
3809
+ f"We do not know how to interpret "
3810
+ f"the assignment node: {ast.dump(node)}",
3811
+ )
3812
+ )
3813
+ continue
3814
+ else:
3815
+ if (
3816
+ isinstance(node.value, ast.Call)
3817
+ and isinstance(node.value.func, ast.Name)
3818
+ and node.value.func.id.startswith("constant_")
3819
+ ):
3820
+ underlying_errors.append(
3821
+ Error(
3822
+ node,
3823
+ f"We do not know how to interpret "
3824
+ f"the assignment: {atok.get_text(node)}. "
3825
+ f"You probably forgot to specify the type annotation "
3826
+ f"for the constant?",
3827
+ )
3828
+ )
3829
+ else:
3830
+ underlying_errors.append(
3831
+ Error(
3832
+ node,
3833
+ f"We do not know how to interpret "
3834
+ f"the assignment: {atok.get_text(node)}",
3835
+ )
3836
+ )
3837
+
3838
+ elif len(node.targets) > 1:
3839
+ underlying_errors.append(
3840
+ Error(
3841
+ node,
3842
+ f"We do not know how to parse a multi-target assignment: "
3843
+ f"{atok.get_text(node)}; in AST: {ast.dump(node)}",
3844
+ )
3845
+ )
3846
+ continue
3847
+
3848
+ elif isinstance(node, ast.AnnAssign):
3849
+ matched = True
3850
+
3851
+ constant, error = _ann_assign_to_constant(node=node, atok=atok)
3852
+ if error is not None:
3853
+ underlying_errors.append(error)
3854
+ continue
3855
+
3856
+ assert constant is not None
3857
+ constants.append(constant)
3858
+ else:
3859
+ matched = False
3860
+
3861
+ if not matched:
3862
+ underlying_errors.append(
3863
+ Error(
3864
+ node, f"We do not know how to parse the AST node: {ast.dump(node)}"
3865
+ )
3866
+ )
3867
+
3868
+ if version is None:
3869
+ underlying_errors.append(
3870
+ Error(
3871
+ None,
3872
+ "The version (given as assignment to ``__version__``) is missing",
3873
+ )
3874
+ )
3875
+
3876
+ if xml_namespace is None:
3877
+ underlying_errors.append(
3878
+ Error(
3879
+ None,
3880
+ "The XML namespace (given as assignment to ``__xml_namespace__``) "
3881
+ "is missing",
3882
+ )
3883
+ )
3884
+
3885
+ duplicate_name_errors = _verify_duplicate_names(
3886
+ itertools.chain(our_types, constants, verification_functions)
3887
+ )
3888
+ if duplicate_name_errors is not None:
3889
+ underlying_errors.append(
3890
+ Error(
3891
+ None,
3892
+ "One or more symbols in the meta-model have duplicate names",
3893
+ duplicate_name_errors,
3894
+ )
3895
+ )
3896
+
3897
+ if len(underlying_errors) > 0:
3898
+ return None, Error(None, "Failed to parse the meta-model", underlying_errors)
3899
+
3900
+ # endregion
3901
+
3902
+ assert version is not None
3903
+ assert xml_namespace is not None
3904
+
3905
+ unverified_symbol_table = UnverifiedSymbolTable(
3906
+ our_types=our_types,
3907
+ constants=constants,
3908
+ verification_functions=verification_functions,
3909
+ meta_model=MetaModel(
3910
+ version=version,
3911
+ xml_namespace=xml_namespace,
3912
+ description=description,
3913
+ ),
3914
+ )
3915
+
3916
+ symbol_table, verification_errors = _verify_symbol_table(unverified_symbol_table)
3917
+
3918
+ if verification_errors is not None:
3919
+ return (
3920
+ None,
3921
+ Error(
3922
+ atok.tree, "Verification of the meta-model failed", verification_errors
3923
+ ),
3924
+ )
3925
+
3926
+ assert symbol_table is not None
3927
+ return symbol_table, None
3928
+
3929
+
3930
+ @require(lambda atok: isinstance(atok.tree, ast.Module))
3931
+ @ensure(lambda result: (result[0] is None) ^ (result[1] is None))
3932
+ def atok_to_symbol_table(
3933
+ atok: asttokens.ASTTokens,
3934
+ ) -> Tuple[Optional[SymbolTable], Optional[Error]]:
3935
+ """Construct the symbol table based on the parsed AST."""
3936
+ table, error = _atok_to_symbol_table(atok=atok)
3937
+ if error is not None:
3938
+ return None, error
3939
+
3940
+ return table, None