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,2266 @@
1
+ """
2
+ Infer the types of the tree nodes.
3
+
4
+ Note that these types roughly follow the type annotations in
5
+ :py:mod:`aas_core_codegen.intermediate._types`, but are not identical. For example,
6
+ the ``LENGTH`` primitive exists only in type inference. Another example, we do not
7
+ track ``parsed`` as the types are inferred in the intermediate stage, but can not
8
+ be traced back to the parse stage.
9
+ """
10
+
11
+ import abc
12
+ import contextlib
13
+ import enum
14
+ from typing import (
15
+ Mapping,
16
+ MutableMapping,
17
+ Optional,
18
+ List,
19
+ Final,
20
+ Union,
21
+ get_args,
22
+ Tuple,
23
+ )
24
+
25
+ from icontract import DBC, ensure, require
26
+
27
+ from aas_core_codegen.common import (
28
+ Identifier,
29
+ Error,
30
+ assert_never,
31
+ assert_union_of_descendants_exhaustive,
32
+ assert_union_without_excluded,
33
+ )
34
+ from aas_core_codegen.intermediate import _types
35
+ from aas_core_codegen.parse import tree as parse_tree
36
+
37
+
38
+ class PrimitiveType(enum.Enum):
39
+ """List primitive types."""
40
+
41
+ BOOL = "bool"
42
+ INT = "int"
43
+ FLOAT = "float"
44
+ STR = "str"
45
+ BYTEARRAY = "bytearray"
46
+
47
+ #: Denote the language-agnostic type returned from ``len(.)``.
48
+ #: Depending on the language, this is not the same as ``INT``.
49
+ LENGTH = "length"
50
+
51
+ #: Denote that the node is a statement and that there is no type
52
+ NONE = "None"
53
+
54
+
55
+ class TypeAnnotation(DBC):
56
+ """Represent an inferred type annotation."""
57
+
58
+ @abc.abstractmethod
59
+ def __str__(self) -> str:
60
+ # Signal that this is a purely abstract class
61
+ raise NotImplementedError()
62
+
63
+
64
+ class AtomicTypeAnnotation(TypeAnnotation):
65
+ """
66
+ Represent an atomic type annotation.
67
+
68
+ Atomic, in this context, means a non-generic type annotation.
69
+
70
+ For example, ``int``.
71
+ """
72
+
73
+ @abc.abstractmethod
74
+ def __str__(self) -> str:
75
+ # Signal that this is a purely abstract class
76
+ raise NotImplementedError()
77
+
78
+
79
+ class PrimitiveTypeAnnotation(AtomicTypeAnnotation):
80
+ """Represent a primitive type such as ``int``."""
81
+
82
+ def __init__(self, a_type: PrimitiveType) -> None:
83
+ """Initialize with the given values."""
84
+ self.a_type = a_type
85
+
86
+ def __str__(self) -> str:
87
+ return str(self.a_type.value)
88
+
89
+
90
+ class OurTypeAnnotation(AtomicTypeAnnotation):
91
+ """
92
+ Represent an atomic annotation defined by our type in the meta-model.
93
+
94
+ For example, ``Asset``.
95
+ """
96
+
97
+ def __init__(self, our_type: _types.OurType) -> None:
98
+ """Initialize with the given values."""
99
+ self.our_type = our_type
100
+
101
+ def __str__(self) -> str:
102
+ return self.our_type.name
103
+
104
+
105
+ class FunctionTypeAnnotation(AtomicTypeAnnotation):
106
+ """Represent a function as a type."""
107
+
108
+ @abc.abstractmethod
109
+ def __str__(self) -> str:
110
+ # Signal that this is a purely abstract class
111
+ raise NotImplementedError()
112
+
113
+
114
+ class VerificationTypeAnnotation(FunctionTypeAnnotation):
115
+ """Represent a type of verification function."""
116
+
117
+ def __init__(self, func: _types.Verification):
118
+ """Initialize with the given values."""
119
+ self.func = func
120
+
121
+ def __str__(self) -> str:
122
+ return self.func.name
123
+
124
+
125
+ class BuiltinFunction:
126
+ """Represent a built-in function."""
127
+
128
+ def __init__(self, name: Identifier, returns: Optional["TypeAnnotationUnion"]):
129
+ """Initialize with the given values."""
130
+ self.name = name
131
+ self.returns = returns
132
+
133
+
134
+ class BuiltinFunctionTypeAnnotation(FunctionTypeAnnotation):
135
+ """Represent a type of built-in function."""
136
+
137
+ def __init__(self, func: BuiltinFunction):
138
+ """Initialize with the given values."""
139
+ self.func = func
140
+
141
+ def __str__(self) -> str:
142
+ return self.func.name
143
+
144
+
145
+ class MethodTypeAnnotation(AtomicTypeAnnotation):
146
+ """Represent a type of class method."""
147
+
148
+ def __init__(self, method: _types.Method):
149
+ """Initialize with the given values."""
150
+ self.method = method
151
+
152
+ def __str__(self) -> str:
153
+ return self.method.name
154
+
155
+
156
+ class SubscriptedTypeAnnotation(TypeAnnotation):
157
+ """Represent a subscripted (i.e. generic) type annotation.
158
+
159
+ The subscripted type annotations are, for example, ``List[...]`` (or
160
+ ``Mapping[..., ...]``, *etc.*).
161
+ """
162
+
163
+ @abc.abstractmethod
164
+ def __str__(self) -> str:
165
+ # Signal that this is a purely abstract class
166
+ raise NotImplementedError()
167
+
168
+
169
+ class ListTypeAnnotation(SubscriptedTypeAnnotation):
170
+ """Represent a type annotation involving a ``List[...]``."""
171
+
172
+ def __init__(self, items: "TypeAnnotationUnion"):
173
+ self.items = items
174
+
175
+ def __str__(self) -> str:
176
+ return f"List[{self.items}]"
177
+
178
+
179
+ class SetTypeAnnotation(SubscriptedTypeAnnotation):
180
+ """Represent a type annotation involving a ``Set[...]``."""
181
+
182
+ def __init__(self, items: "TypeAnnotationUnion"):
183
+ self.items = items
184
+
185
+ def __str__(self) -> str:
186
+ return f"Set[{self.items}]"
187
+
188
+
189
+ class OptionalTypeAnnotation(SubscriptedTypeAnnotation):
190
+ """Represent a type annotation involving an ``Optional[...]``."""
191
+
192
+ def __init__(self, value: "TypeAnnotationUnion"):
193
+ self.value = value
194
+
195
+ def __str__(self) -> str:
196
+ return f"Optional[{self.value}]"
197
+
198
+
199
+ class EnumerationAsTypeTypeAnnotation(TypeAnnotation):
200
+ """
201
+ Represent an enum class as a type.
202
+
203
+ Note that this is not the enum as a type of that enum class, but
204
+ rather the type-as-a-type. We write``Type[T]`` in Python to describe this.
205
+ """
206
+
207
+ # NOTE (mristin, 2022-02-04):
208
+ # The name of this class is admittedly clumsy. Please feel free to change if you
209
+ # come up with a better idea.
210
+
211
+ def __init__(self, enumeration: _types.Enumeration) -> None:
212
+ """Initialize with the given values."""
213
+ self.enumeration = enumeration
214
+
215
+ def __str__(self) -> str:
216
+ return f"{self.__class__.__name__}[{self.enumeration}]"
217
+
218
+
219
+ def beneath_optional(
220
+ type_annotation: "TypeAnnotationUnion",
221
+ ) -> "TypeAnnotationExceptOptional":
222
+ """Recurse over optionals until we reach a non-optional."""
223
+ while isinstance(type_annotation, OptionalTypeAnnotation):
224
+ type_annotation = type_annotation.value
225
+
226
+ return type_annotation
227
+
228
+
229
+ def _type_annotations_equal(
230
+ that: "TypeAnnotationUnion", other: "TypeAnnotationUnion"
231
+ ) -> bool:
232
+ """Check whether the ``that`` and ``other`` type annotations are identical."""
233
+ if isinstance(that, PrimitiveTypeAnnotation):
234
+ if not isinstance(other, PrimitiveTypeAnnotation):
235
+ return False
236
+ else:
237
+ return that.a_type == other.a_type
238
+
239
+ elif isinstance(that, OurTypeAnnotation):
240
+ if not isinstance(other, OurTypeAnnotation):
241
+ return False
242
+ else:
243
+ return that.our_type is other.our_type
244
+
245
+ elif isinstance(that, VerificationTypeAnnotation):
246
+ if not isinstance(other, VerificationTypeAnnotation):
247
+ return False
248
+ else:
249
+ return that.func is other.func
250
+
251
+ elif isinstance(that, BuiltinFunctionTypeAnnotation):
252
+ if not isinstance(other, BuiltinFunctionTypeAnnotation):
253
+ return False
254
+ else:
255
+ return that.func is other.func
256
+
257
+ elif isinstance(that, MethodTypeAnnotation):
258
+ if not isinstance(other, MethodTypeAnnotation):
259
+ return False
260
+ else:
261
+ return that.method is other.method
262
+
263
+ elif isinstance(that, ListTypeAnnotation):
264
+ if not isinstance(other, ListTypeAnnotation):
265
+ return False
266
+ else:
267
+ return _type_annotations_equal(that.items, other.items)
268
+
269
+ elif isinstance(that, SetTypeAnnotation):
270
+ if not isinstance(other, SetTypeAnnotation):
271
+ return False
272
+ else:
273
+ return _type_annotations_equal(that.items, other.items)
274
+
275
+ elif isinstance(that, OptionalTypeAnnotation):
276
+ if not isinstance(other, OptionalTypeAnnotation):
277
+ return False
278
+ else:
279
+ return _type_annotations_equal(that.value, other.value)
280
+
281
+ elif isinstance(that, EnumerationAsTypeTypeAnnotation):
282
+ if not isinstance(other, EnumerationAsTypeTypeAnnotation):
283
+ return False
284
+ else:
285
+ return that.enumeration is other.enumeration
286
+
287
+ else:
288
+ assert_never(that)
289
+
290
+ raise AssertionError("Should not have gotten here")
291
+
292
+
293
+ PRIMITIVE_TYPE_MAP = {
294
+ _types.PrimitiveType.BOOL: PrimitiveType.BOOL,
295
+ _types.PrimitiveType.INT: PrimitiveType.INT,
296
+ _types.PrimitiveType.FLOAT: PrimitiveType.FLOAT,
297
+ _types.PrimitiveType.STR: PrimitiveType.STR,
298
+ _types.PrimitiveType.BYTEARRAY: PrimitiveType.BYTEARRAY,
299
+ }
300
+
301
+
302
+ def _assignable(
303
+ target_type: "TypeAnnotationUnion", value_type: "TypeAnnotationUnion"
304
+ ) -> bool:
305
+ """Check whether the value can be assigned to the target."""
306
+ if isinstance(target_type, PrimitiveTypeAnnotation):
307
+ if isinstance(value_type, PrimitiveTypeAnnotation):
308
+ return target_type.a_type == value_type.a_type
309
+
310
+ # NOTE (mristin, 2021-12-25):
311
+ # We have to be careful about the constrained primitives,
312
+ # since we can always assign a constrained primitive to a primitive, if they
313
+ # primitive types match.
314
+ elif isinstance(value_type, OurTypeAnnotation) and isinstance(
315
+ value_type.our_type, _types.ConstrainedPrimitive
316
+ ):
317
+ return (
318
+ target_type.a_type
319
+ == PRIMITIVE_TYPE_MAP[value_type.our_type.constrainee]
320
+ )
321
+
322
+ else:
323
+ return False
324
+
325
+ elif isinstance(target_type, OurTypeAnnotation):
326
+ if isinstance(target_type.our_type, _types.Enumeration):
327
+ # NOTE (mristin, 2021-12-25):
328
+ # The enumerations are invariant.
329
+ return (
330
+ isinstance(value_type, OurTypeAnnotation)
331
+ and isinstance(value_type.our_type, _types.Enumeration)
332
+ and target_type.our_type is value_type.our_type
333
+ )
334
+
335
+ elif isinstance(target_type.our_type, _types.ConstrainedPrimitive):
336
+ # NOTE (mristin, 2021-12-25):
337
+ # If it is a constrained primitive with no constraints, allow the assignment
338
+ # if the target and the value match on the primitive type.
339
+ if len(target_type.our_type.invariants) == 0 and isinstance(
340
+ value_type, PrimitiveTypeAnnotation
341
+ ):
342
+ return (
343
+ PRIMITIVE_TYPE_MAP[target_type.our_type.constrainee]
344
+ == value_type.a_type
345
+ )
346
+ else:
347
+ # NOTE (mristin, 2021-12-25):
348
+ # We assume the assignments of constrained primitives to be co-variant.
349
+ if (
350
+ isinstance(value_type, OurTypeAnnotation)
351
+ and isinstance(value_type.our_type, _types.ConstrainedPrimitive)
352
+ and target_type.our_type.constrainee
353
+ == value_type.our_type.constrainee
354
+ ):
355
+ return (
356
+ target_type.our_type is value_type.our_type
357
+ or id(value_type.our_type)
358
+ in target_type.our_type.descendant_id_set
359
+ )
360
+
361
+ return False
362
+
363
+ elif isinstance(target_type.our_type, _types.Class):
364
+ if not (
365
+ isinstance(value_type, OurTypeAnnotation)
366
+ and isinstance(value_type.our_type, _types.Class)
367
+ ):
368
+ return False
369
+
370
+ # NOTE (mristin, 2021-12-25):
371
+ # We assume the assignment to be co-variant. Either the target type and
372
+ # the value type are equal *or* the value type is a descendant of the
373
+ # target type.
374
+
375
+ return target_type.our_type is value_type.our_type or (
376
+ id(value_type.our_type) in target_type.our_type.descendant_id_set
377
+ )
378
+
379
+ elif isinstance(target_type, VerificationTypeAnnotation):
380
+ if not isinstance(value_type, VerificationTypeAnnotation):
381
+ return False
382
+ else:
383
+ return target_type.func is value_type.func
384
+
385
+ elif isinstance(target_type, BuiltinFunctionTypeAnnotation):
386
+ if not isinstance(value_type, BuiltinFunctionTypeAnnotation):
387
+ return False
388
+ else:
389
+ return target_type.func is value_type.func
390
+
391
+ elif isinstance(target_type, MethodTypeAnnotation):
392
+ if not isinstance(value_type, MethodTypeAnnotation):
393
+ return False
394
+ else:
395
+ return target_type.method is value_type.method
396
+
397
+ elif isinstance(target_type, ListTypeAnnotation):
398
+ if not isinstance(value_type, ListTypeAnnotation):
399
+ return False
400
+ else:
401
+ # NOTE (mristin, 2021-12-25):
402
+ # We assume the lists to be invariant. This is necessary for code generation
403
+ # in implementation targets such as C++ and Golang.
404
+ return _type_annotations_equal(target_type.items, value_type.items)
405
+
406
+ elif isinstance(target_type, SetTypeAnnotation):
407
+ if not isinstance(value_type, SetTypeAnnotation):
408
+ return False
409
+ else:
410
+ # NOTE (mristin, 2021-12-25):
411
+ # We assume the sets to be invariant. This is necessary for code generation
412
+ # in implementation targets such as C++ and Golang.
413
+ return _type_annotations_equal(target_type.items, value_type.items)
414
+
415
+ elif isinstance(target_type, OptionalTypeAnnotation):
416
+ # NOTE (mristin, 2021-12-25):
417
+ # We can always assign a non-optional to an optional.
418
+ if not isinstance(value_type, OptionalTypeAnnotation):
419
+ return _assignable(target_type=target_type.value, value_type=value_type)
420
+ else:
421
+ # NOTE (mristin, 2021-12-25):
422
+ # We assume the optionals to be co-variant.
423
+ return _assignable(
424
+ target_type=target_type.value, value_type=value_type.value
425
+ )
426
+
427
+ elif isinstance(target_type, EnumerationAsTypeTypeAnnotation):
428
+ raise NotImplementedError(
429
+ "(mristin, 2022-02-04): Assigning enumeration-as-type to another "
430
+ "enumeration-as-type is a very niche program logic. As we do not have "
431
+ "a concrete example of such an assignment, we currently ignore this case "
432
+ "in determining whether the assignment makes sense. When you have "
433
+ "a concrete example, please revisit this part of the code."
434
+ )
435
+
436
+ else:
437
+ assert_never(target_type)
438
+
439
+ return False
440
+
441
+
442
+ for _types_primitive_type in _types.PrimitiveType:
443
+ assert (
444
+ _types_primitive_type in PRIMITIVE_TYPE_MAP
445
+ ), f"All primitive types from _types covered, but: {_types_primitive_type=}"
446
+
447
+
448
+ def convert_type_annotation(
449
+ type_annotation: _types.TypeAnnotationUnion,
450
+ ) -> "TypeAnnotationUnion":
451
+ """
452
+ Convert from the :py:mod:`aas_core_codegen.intermediate._types`.
453
+
454
+ We can not use the same type annotations as type inference uses a wider set of
455
+ type annotations such as ``LENGTH`` in primitives or enumeration-as-type.
456
+ """
457
+ if isinstance(type_annotation, _types.PrimitiveTypeAnnotation):
458
+ return PrimitiveTypeAnnotation(
459
+ a_type=PRIMITIVE_TYPE_MAP[type_annotation.a_type]
460
+ )
461
+
462
+ elif isinstance(type_annotation, _types.OurTypeAnnotation):
463
+ return OurTypeAnnotation(our_type=type_annotation.our_type)
464
+
465
+ elif isinstance(type_annotation, _types.ListTypeAnnotation):
466
+ return ListTypeAnnotation(items=convert_type_annotation(type_annotation.items))
467
+
468
+ elif isinstance(type_annotation, _types.OptionalTypeAnnotation):
469
+ return OptionalTypeAnnotation(
470
+ value=convert_type_annotation(type_annotation.value)
471
+ )
472
+
473
+ else:
474
+ assert_never(type_annotation)
475
+
476
+ raise AssertionError("Should not have gotten here")
477
+
478
+
479
+ class Environment(DBC):
480
+ """
481
+ Map names to type annotations for a given scope.
482
+
483
+ We first search in the given scope and then iterate over the ancestor scopes.
484
+ See, for example: https://craftinginterpreters.com/resolving-and-binding.html.
485
+
486
+ The most outer, global, scope is parentless.
487
+ """
488
+
489
+ def __init__(self, parent: Optional["Environment"]) -> None:
490
+ """Initialize with the given values."""
491
+ self.parent = parent
492
+
493
+ @property
494
+ @abc.abstractmethod
495
+ def mapping(self) -> Mapping[Identifier, "TypeAnnotationUnion"]:
496
+ """Retrieve the underlying mapping."""
497
+ raise NotImplementedError()
498
+
499
+ def find(self, identifier: Identifier) -> Optional["TypeAnnotationUnion"]:
500
+ """
501
+ Search for the type annotation of the given ``identifier``.
502
+
503
+ We search all the way to the most outer scope.
504
+ """
505
+ type_anno = self.mapping.get(identifier, None)
506
+ if type_anno is not None:
507
+ return type_anno
508
+
509
+ if self.parent is not None:
510
+ return self.parent.find(identifier)
511
+
512
+ return None
513
+
514
+
515
+ class ImmutableEnvironment(Environment):
516
+ """
517
+ Map immutably names to type annotations for a given scope.
518
+ """
519
+
520
+ def __init__(
521
+ self,
522
+ mapping: Mapping[Identifier, "TypeAnnotationUnion"],
523
+ parent: Optional["Environment"] = None,
524
+ ) -> None:
525
+ self._mapping = mapping
526
+
527
+ Environment.__init__(self, parent)
528
+
529
+ @property
530
+ def mapping(self) -> Mapping[Identifier, "TypeAnnotationUnion"]:
531
+ """Retrieve the underlying mapping."""
532
+ return self._mapping
533
+
534
+
535
+ class MutableEnvironment(Environment):
536
+ """
537
+ Map names to type annotations for a given scope and allow mutations.
538
+ """
539
+
540
+ def __init__(self, parent: Optional["Environment"] = None) -> None:
541
+ self._mapping = (
542
+ dict()
543
+ ) # type: MutableMapping[Identifier, "TypeAnnotationUnion"]
544
+
545
+ Environment.__init__(self, parent)
546
+
547
+ @property
548
+ def mapping(self) -> Mapping[Identifier, "TypeAnnotationUnion"]:
549
+ """Retrieve the underlying mapping."""
550
+ return self._mapping
551
+
552
+ def set(
553
+ self, identifier: Identifier, type_annotation: "TypeAnnotationUnion"
554
+ ) -> None:
555
+ """Set the ``type_annotation`` for the given ``identifier``."""
556
+ self._mapping[identifier] = type_annotation
557
+
558
+ def remove(self, identifier: Identifier) -> None:
559
+ """
560
+ Remove the entry in the environment for the ``identifier``.
561
+
562
+ For example, you need to do this if you have temporary scopes such as generator
563
+ expressions where a long linked list of environments would be neither
564
+ performant nor readable during the debugging.
565
+ """
566
+ del self._mapping[identifier]
567
+
568
+
569
+ class _Canonicalizer(parse_tree.RestrictedTransformer[str]):
570
+ """Represent the nodes as canonical strings so that they can be used in look-ups."""
571
+
572
+ #: Track of the canonical representations
573
+ representation_map: Final[MutableMapping[parse_tree.Node, str]]
574
+
575
+ def __init__(self) -> None:
576
+ """Initialize with the given values."""
577
+ self.representation_map = dict()
578
+
579
+ @ensure(lambda self, node: node in self.representation_map)
580
+ def transform(self, node: parse_tree.Node) -> str:
581
+ return super().transform(node)
582
+
583
+ @staticmethod
584
+ def _needs_no_brackets(node: parse_tree.Node) -> bool:
585
+ """
586
+ Check if the representation needs brackets for unambiguity.
587
+
588
+ While we could always put brackets, they harm readability in later debugging, so
589
+ we try to make the representation as readable as possible.
590
+ """
591
+ return isinstance(
592
+ node,
593
+ (
594
+ parse_tree.Member,
595
+ parse_tree.MethodCall,
596
+ parse_tree.Name,
597
+ parse_tree.FunctionCall,
598
+ parse_tree.Constant,
599
+ parse_tree.JoinedStr,
600
+ parse_tree.Any,
601
+ parse_tree.All,
602
+ ),
603
+ )
604
+
605
+ def transform_member(self, node: parse_tree.Member) -> str:
606
+ instance_repr = self.transform(node.instance)
607
+
608
+ if _Canonicalizer._needs_no_brackets(node.instance):
609
+ result = f"{instance_repr}.{node.name}"
610
+ else:
611
+ result = f"({instance_repr}).{node.name}"
612
+
613
+ self.representation_map[node] = result
614
+ return result
615
+
616
+ def transform_index(self, node: parse_tree.Index) -> str:
617
+ collection_repr = self.transform(node.collection)
618
+ index_repr = self.transform(node.index)
619
+
620
+ if _Canonicalizer._needs_no_brackets(node.collection):
621
+ result = f"{collection_repr}[{index_repr}]"
622
+ else:
623
+ result = f"({collection_repr})[{index_repr}]"
624
+
625
+ self.representation_map[node] = result
626
+ return result
627
+
628
+ def transform_comparison(self, node: parse_tree.Comparison) -> str:
629
+ left = self.transform(node.left)
630
+ if not _Canonicalizer._needs_no_brackets(node.left):
631
+ left = f"({left})"
632
+
633
+ right = self.transform(node.right)
634
+ if not _Canonicalizer._needs_no_brackets(node.right):
635
+ right = f"({right})"
636
+
637
+ result = f"{left} {node.op.value} {right}"
638
+ self.representation_map[node] = result
639
+ return result
640
+
641
+ def transform_is_in(self, node: parse_tree.IsIn) -> str:
642
+ member = self.transform(node.member)
643
+ if not _Canonicalizer._needs_no_brackets(node.member):
644
+ member = f"({member})"
645
+
646
+ container = self.transform(node.container)
647
+ if not _Canonicalizer._needs_no_brackets(node.container):
648
+ container = f"({container})"
649
+
650
+ result = f"{member} in {container}"
651
+ self.representation_map[node] = result
652
+ return result
653
+
654
+ def transform_implication(self, node: parse_tree.Implication) -> str:
655
+ antecedent = self.transform(node.antecedent)
656
+ if not _Canonicalizer._needs_no_brackets(node.antecedent):
657
+ antecedent = f"({antecedent})"
658
+
659
+ consequent = self.transform(node.consequent)
660
+ if not _Canonicalizer._needs_no_brackets(node.consequent):
661
+ consequent = f"({consequent})"
662
+
663
+ result = f"{antecedent} ⇒ {consequent}"
664
+ self.representation_map[node] = result
665
+ return result
666
+
667
+ def transform_method_call(self, node: parse_tree.MethodCall) -> str:
668
+ member = self.transform(node.member)
669
+
670
+ args = [self.transform(arg) for arg in node.args]
671
+
672
+ args_joined = ", ".join(args)
673
+ result = f"{member}({args_joined})"
674
+ self.representation_map[node] = result
675
+ return result
676
+
677
+ def transform_function_call(self, node: parse_tree.FunctionCall) -> str:
678
+ name = self.transform(node.name)
679
+
680
+ args = [self.transform(arg) for arg in node.args]
681
+
682
+ args_joined = ", ".join(args)
683
+ result = f"{name}({args_joined})"
684
+ self.representation_map[node] = result
685
+ return result
686
+
687
+ def transform_constant(self, node: parse_tree.Constant) -> str:
688
+ result = repr(node.value)
689
+ self.representation_map[node] = result
690
+ return result
691
+
692
+ def transform_is_none(self, node: parse_tree.IsNone) -> str:
693
+ value = self.transform(node.value)
694
+ if not _Canonicalizer._needs_no_brackets(node.value):
695
+ value = f"({value})"
696
+
697
+ result = f"{value} is None"
698
+ self.representation_map[node] = result
699
+ return result
700
+
701
+ def transform_is_not_none(self, node: parse_tree.IsNotNone) -> str:
702
+ value = self.transform(node.value)
703
+ if not _Canonicalizer._needs_no_brackets(node.value):
704
+ value = f"({value})"
705
+
706
+ result = f"{value} is not None"
707
+ self.representation_map[node] = result
708
+ return result
709
+
710
+ def transform_name(self, node: parse_tree.Name) -> str:
711
+ result = node.identifier
712
+ self.representation_map[node] = result
713
+ return result
714
+
715
+ def transform_not(self, node: parse_tree.Not) -> str:
716
+ operand_repr = self.transform(node.operand)
717
+
718
+ if not _Canonicalizer._needs_no_brackets(node):
719
+ operand_repr = f"({operand_repr})"
720
+
721
+ result = f"not {operand_repr}"
722
+ self.representation_map[node] = result
723
+ return result
724
+
725
+ def transform_and(self, node: parse_tree.And) -> str:
726
+ values = [] # type: List[str]
727
+
728
+ for value_node in node.values:
729
+ value = self.transform(value_node)
730
+ if not _Canonicalizer._needs_no_brackets(value_node):
731
+ value = f"({value})"
732
+
733
+ values.append(value)
734
+
735
+ result = " and ".join(values)
736
+ self.representation_map[node] = result
737
+ return result
738
+
739
+ def transform_or(self, node: parse_tree.Or) -> str:
740
+ values = [] # type: List[str]
741
+ for value_node in node.values:
742
+ value = self.transform(value_node)
743
+ if not _Canonicalizer._needs_no_brackets(value_node):
744
+ value = f"({value})"
745
+
746
+ values.append(value)
747
+
748
+ result = " or ".join(values)
749
+ self.representation_map[node] = result
750
+ return result
751
+
752
+ def _transform_add_or_sub(self, node: Union[parse_tree.Add, parse_tree.Sub]) -> str:
753
+ left_repr = self.transform(node.left)
754
+ if not _Canonicalizer._needs_no_brackets(node.left):
755
+ left_repr = f"({left_repr})"
756
+
757
+ right_repr = self.transform(node.right)
758
+ if not _Canonicalizer._needs_no_brackets(node.right):
759
+ right_repr = f"({right_repr})"
760
+
761
+ result: str
762
+ if isinstance(node, parse_tree.Add):
763
+ result = f"{left_repr} + {right_repr}"
764
+ elif isinstance(node, parse_tree.Sub):
765
+ result = f"{left_repr} - {right_repr}"
766
+ else:
767
+ assert_never(node)
768
+
769
+ self.representation_map[node] = result
770
+ return result
771
+
772
+ def transform_add(self, node: parse_tree.Add) -> str:
773
+ return self._transform_add_or_sub(node)
774
+
775
+ def transform_sub(self, node: parse_tree.Sub) -> str:
776
+ return self._transform_add_or_sub(node)
777
+
778
+ def transform_formatted_value(self, node: parse_tree.FormattedValue) -> str:
779
+ result = self.transform(node.value)
780
+ self.representation_map[node] = result
781
+ return result
782
+
783
+ def transform_joined_str(self, node: parse_tree.JoinedStr) -> str:
784
+ parts = [] # type: List[str]
785
+ for value in node.values:
786
+ if isinstance(value, str):
787
+ parts.append(repr(value))
788
+ elif isinstance(value, parse_tree.FormattedValue):
789
+ transformed_value = self.transform(value)
790
+ parts.append(f"{{{transformed_value}}}")
791
+ else:
792
+ assert_never(value)
793
+
794
+ result = "".join(parts)
795
+ self.representation_map[node] = result
796
+ return result
797
+
798
+ def transform_for_each(self, node: parse_tree.ForEach) -> str:
799
+ variable = self.transform(node.variable)
800
+ iteration = self.transform(node.iteration)
801
+ if not _Canonicalizer._needs_no_brackets(node.iteration):
802
+ iteration = f"({iteration})"
803
+
804
+ result = f"for {variable} in {iteration}"
805
+ self.representation_map[node] = result
806
+ return result
807
+
808
+ def transform_for_range(self, node: parse_tree.ForRange) -> str:
809
+ variable = self.transform(node.variable)
810
+ start = self.transform(node.start)
811
+ end = self.transform(node.end)
812
+
813
+ result = f"for {variable} in range({start}, {end})"
814
+ self.representation_map[node] = result
815
+ return result
816
+
817
+ def _transform_any_or_all(self, node: Union[parse_tree.Any, parse_tree.All]) -> str:
818
+ generator = self.transform(node.generator)
819
+
820
+ condition = self.transform(node.condition)
821
+ if not _Canonicalizer._needs_no_brackets(node.condition):
822
+ condition = f"({condition})"
823
+
824
+ result: str
825
+
826
+ if isinstance(node, parse_tree.Any):
827
+ result = f"any({condition} {generator})"
828
+ elif isinstance(node, parse_tree.All):
829
+ result = f"all({condition} {generator})"
830
+ else:
831
+ assert_never(node)
832
+
833
+ self.representation_map[node] = result
834
+ return result
835
+
836
+ def transform_any(self, node: parse_tree.Any) -> str:
837
+ return self._transform_any_or_all(node)
838
+
839
+ def transform_all(self, node: parse_tree.All) -> str:
840
+ return self._transform_any_or_all(node)
841
+
842
+ def transform_assignment(self, node: parse_tree.Assignment) -> str:
843
+ target = self.transform(node.target)
844
+ if not _Canonicalizer._needs_no_brackets(node.target):
845
+ target = f"({target})"
846
+
847
+ # NOTE (mristin, 2022-06-17):
848
+ # Nested assignments are not possible in Python, but who knows where our
849
+ # intermediate representation will take us. Therefore, we handle this edge case
850
+ # even though it seems nonsensical at the moment.
851
+ value = self.transform(node.value)
852
+ if isinstance(node.value, parse_tree.Assignment):
853
+ value = f"({value})"
854
+
855
+ result = f"{target} = {value}"
856
+
857
+ self.representation_map[node] = result
858
+ return result
859
+
860
+ def transform_return(self, node: parse_tree.Return) -> str:
861
+ if node.value is not None:
862
+ value = self.transform(node.value)
863
+
864
+ # NOTE (mristin, 2022-06-17):
865
+ # Nested returns are not possible in Python, but who knows where our
866
+ # intermediate representation will take us. Therefore, we handle
867
+ # this edge case even though it seems nonsensical at the moment.
868
+ if isinstance(node.value, parse_tree.Return):
869
+ value = f"({value})"
870
+
871
+ result = f"return {value}"
872
+ else:
873
+ result = "return"
874
+
875
+ self.representation_map[node] = result
876
+ return result
877
+
878
+
879
+ class _CountingMap:
880
+ """Provide a map to track multiple counters."""
881
+
882
+ def __init__(self) -> None:
883
+ self._counts = dict() # type: MutableMapping[str, int]
884
+
885
+ def increment(self, key: str) -> None:
886
+ """Increment the counter for the ``key``."""
887
+ count = self._counts.get(key, None)
888
+ if count is None:
889
+ self._counts[key] = 1
890
+ else:
891
+ self._counts[key] = count + 1
892
+
893
+ @ensure(lambda self, key, result: not result or self.count(key) > 0)
894
+ @ensure(lambda self, key, result: result or self.count(key) == 0)
895
+ def at_least_once(self, key: str) -> bool:
896
+ """Return ``True`` if the ``key`` is tracked and the count is at least 1."""
897
+ count = self.count(key)
898
+ return count >= 1
899
+
900
+ @ensure(lambda result: result >= 0)
901
+ def count(self, key: str) -> int:
902
+ """Return the number of stacked ``key``'s."""
903
+ result = self._counts.get(key, None)
904
+ return 0 if result is None else result
905
+
906
+ # fmt: off
907
+ @require(
908
+ lambda self, key:
909
+ self.at_least_once(key),
910
+ "Can not decrement past 1"
911
+ )
912
+ # fmt: on
913
+ def decrement(self, key: str) -> None:
914
+ """Decrement the counter for the ``key``."""
915
+ count = self._counts.get(key, None)
916
+
917
+ if count is None or count == 0:
918
+ raise AssertionError(f"Unexpected count == 0 for key {key!r}")
919
+ elif count < 0:
920
+ raise AssertionError(f"Unexpected count < 0 for key {key!r}")
921
+ elif count == 1:
922
+ del self._counts[key]
923
+ else:
924
+ self._counts[key] = count - 1
925
+
926
+
927
+ TypeAnnotationUnion = Union[
928
+ PrimitiveTypeAnnotation,
929
+ OurTypeAnnotation,
930
+ VerificationTypeAnnotation,
931
+ BuiltinFunctionTypeAnnotation,
932
+ MethodTypeAnnotation,
933
+ ListTypeAnnotation,
934
+ SetTypeAnnotation,
935
+ OptionalTypeAnnotation,
936
+ EnumerationAsTypeTypeAnnotation,
937
+ ]
938
+
939
+
940
+ class _Inferrer(parse_tree.RestrictedTransformer[Optional["TypeAnnotationUnion"]]):
941
+ """
942
+ Infer the types of the given parse tree.
943
+
944
+ Since we also handle non-nullness, you need to pre-compute the canonical
945
+ representation of the nodes that you want to infer the types for. To that end,
946
+ use :class:`~CanonicalRepresenter`.
947
+ """
948
+
949
+ #: Track of the inferred types
950
+ type_map: Final[MutableMapping[parse_tree.Node, "TypeAnnotationUnion"]]
951
+
952
+ #: Errors encountered during the inference
953
+ errors: Final[List[Error]]
954
+
955
+ def __init__(
956
+ self,
957
+ environment: "Environment",
958
+ representation_map: Mapping[parse_tree.Node, str],
959
+ ) -> None:
960
+ """Initialize with the given values."""
961
+ # We need to create our own child environment so that we can introduce new
962
+ # entries without affecting the variables from the outer scopes.
963
+ self._environment = MutableEnvironment(parent=environment)
964
+
965
+ self._representation_map = representation_map
966
+
967
+ # NOTE (mristin, 2022-06-17):
968
+ # We need to keep track of the expressions that can be assumed to be non-null.
969
+ # This member is stateful! It will constantly change, depending on the position
970
+ # of the iteration through the tree.
971
+ #
972
+ # We use canonical representation from ``representation_map`` to associate
973
+ # non-null assumptions with the expressions.
974
+ self._non_null = _CountingMap()
975
+
976
+ self.type_map = dict()
977
+ self.errors = []
978
+
979
+ def _strip_optional_if_non_null(
980
+ self, node: parse_tree.Node, type_annotation: "TypeAnnotationUnion"
981
+ ) -> "TypeAnnotationUnion":
982
+ """
983
+ Remove ``Optional`` from the ``type_annotation`` if the ``node`` is non-null.
984
+
985
+ The ``type_annotation`` refers to the type inferred for the ``node``.
986
+
987
+ We keep track of the non-nullness over the iteration in :attr:`._non_null`.
988
+ Using the canonical representation of the ``node``, we can check whether
989
+ the type of the ``node`` is non-null.
990
+ """
991
+ if not isinstance(type_annotation, OptionalTypeAnnotation):
992
+ return type_annotation
993
+
994
+ canonical_repr = self._representation_map[node]
995
+ if self._non_null.at_least_once(canonical_repr):
996
+ return type_annotation.value
997
+
998
+ return type_annotation
999
+
1000
+ @ensure(lambda self, result: not (result is None) or len(self.errors) > 0)
1001
+ def transform(self, node: parse_tree.Node) -> Optional["TypeAnnotationUnion"]:
1002
+ # NOTE (mristin, 2022-06-17):
1003
+ # We can not write the following as the pre-condition as it would break
1004
+ # behavioral subtyping since the parent class expects no pre-conditions.
1005
+ #
1006
+ # However, in this case, we check that the supplied dependency,
1007
+ # ``representation_map``, is correct.
1008
+ assert node in self._representation_map, (
1009
+ f"The node {parse_tree.dump(node)} at 0x{id(node):x} could not be found "
1010
+ f"in the supplied representation_map."
1011
+ )
1012
+
1013
+ return super().transform(node)
1014
+
1015
+ def transform_member(
1016
+ self, node: parse_tree.Member
1017
+ ) -> Optional["TypeAnnotationUnion"]:
1018
+ instance_type = self.transform(node.instance)
1019
+
1020
+ if instance_type is None:
1021
+ return None
1022
+
1023
+ if isinstance(instance_type, OurTypeAnnotation):
1024
+ if not isinstance(instance_type.our_type, _types.Class):
1025
+ self.errors.append(
1026
+ Error(
1027
+ node.instance.original_node,
1028
+ f"Expected an instance type as our type to be a class, "
1029
+ f"but got: {instance_type.our_type}",
1030
+ )
1031
+ )
1032
+ return None
1033
+
1034
+ cls = instance_type.our_type
1035
+ assert isinstance(cls, _types.Class)
1036
+
1037
+ prop = cls.properties_by_name.get(node.name, None)
1038
+ if prop is not None:
1039
+ result = convert_type_annotation(prop.type_annotation)
1040
+
1041
+ result = self._strip_optional_if_non_null(
1042
+ node=node, type_annotation=result
1043
+ )
1044
+ self.type_map[node] = result
1045
+ return result
1046
+
1047
+ method = cls.methods_by_name.get(node.name, None)
1048
+ if method is not None:
1049
+ result = MethodTypeAnnotation(method=method)
1050
+
1051
+ result = self._strip_optional_if_non_null(
1052
+ node=node, type_annotation=result
1053
+ )
1054
+ self.type_map[node] = result
1055
+ return result
1056
+
1057
+ self.errors.append(
1058
+ Error(
1059
+ node.original_node,
1060
+ f"The member {node.name!r} could not be found "
1061
+ f"in the class {cls.name!r}",
1062
+ )
1063
+ )
1064
+
1065
+ elif isinstance(instance_type, EnumerationAsTypeTypeAnnotation):
1066
+ enumeration = instance_type.enumeration
1067
+ literal = enumeration.literals_by_name.get(node.name, None)
1068
+ if literal is not None:
1069
+ result = OurTypeAnnotation(our_type=enumeration)
1070
+
1071
+ result = self._strip_optional_if_non_null(
1072
+ node=node, type_annotation=result
1073
+ )
1074
+ self.type_map[node] = result
1075
+ return result
1076
+
1077
+ self.errors.append(
1078
+ Error(
1079
+ node.original_node,
1080
+ f"The literal {node.name!r} could not be found "
1081
+ f"in the enumeration {enumeration.name!r}",
1082
+ )
1083
+ )
1084
+ else:
1085
+ if isinstance(instance_type, OptionalTypeAnnotation):
1086
+ self.errors.append(
1087
+ Error(
1088
+ node.instance.original_node,
1089
+ f"Expected an instance type to be a non-None, either "
1090
+ f"an enumeration-as-type or our type, "
1091
+ f"but inferred an Optional: {instance_type}",
1092
+ )
1093
+ )
1094
+ else:
1095
+ self.errors.append(
1096
+ Error(
1097
+ node.instance.original_node,
1098
+ f"Expected an instance type to be either "
1099
+ f"an enumeration-as-type or our type, "
1100
+ f"but inferred: {instance_type}",
1101
+ )
1102
+ )
1103
+ return None
1104
+
1105
+ return None
1106
+
1107
+ def transform_index(
1108
+ self, node: parse_tree.Index
1109
+ ) -> Optional["TypeAnnotationUnion"]:
1110
+ collection_type = self.transform(node.collection)
1111
+ if collection_type is None:
1112
+ return None
1113
+
1114
+ index_type = self.transform(node.index)
1115
+ if index_type is None:
1116
+ return None
1117
+
1118
+ success = True
1119
+
1120
+ if isinstance(collection_type, OptionalTypeAnnotation):
1121
+ self.errors.append(
1122
+ Error(
1123
+ node.collection.original_node,
1124
+ f"Expected the collection to be a non-None, "
1125
+ f"but got: {collection_type}",
1126
+ )
1127
+ )
1128
+ success = False
1129
+
1130
+ if isinstance(index_type, OptionalTypeAnnotation):
1131
+ self.errors.append(
1132
+ Error(
1133
+ node.index.original_node,
1134
+ f"Expected the index to be a non-None, " f"but got: {index_type}",
1135
+ )
1136
+ )
1137
+ success = False
1138
+
1139
+ if not success:
1140
+ return None
1141
+
1142
+ if not isinstance(collection_type, ListTypeAnnotation):
1143
+ self.errors.append(
1144
+ Error(
1145
+ node.collection.original_node,
1146
+ f"Expected an index access on a list, but got: {collection_type}",
1147
+ )
1148
+ )
1149
+ return None
1150
+
1151
+ if not (
1152
+ isinstance(index_type, PrimitiveTypeAnnotation)
1153
+ and index_type.a_type in (PrimitiveType.INT, PrimitiveType.LENGTH)
1154
+ ):
1155
+ self.errors.append(
1156
+ Error(
1157
+ node.collection.original_node,
1158
+ f"Expected the index to be an integer, but got: {index_type}",
1159
+ )
1160
+ )
1161
+ return None
1162
+
1163
+ result = collection_type.items
1164
+ self.type_map[node] = result
1165
+ return result
1166
+
1167
+ def transform_comparison(
1168
+ self, node: parse_tree.Comparison
1169
+ ) -> Optional["TypeAnnotationUnion"]:
1170
+ # Just recurse to fill ``type_map`` on ``left`` and ``right`` even though we
1171
+ # know the type in advance
1172
+
1173
+ left_type = self.transform(node.left)
1174
+ if left_type is None:
1175
+ return None
1176
+
1177
+ right_type = self.transform(node.right)
1178
+ if right_type is None:
1179
+ return None
1180
+
1181
+ success = True
1182
+
1183
+ if isinstance(left_type, OptionalTypeAnnotation):
1184
+ self.errors.append(
1185
+ Error(
1186
+ node.left.original_node,
1187
+ f"Expected the left operand to be a non-None, "
1188
+ f"but got: {left_type}",
1189
+ )
1190
+ )
1191
+ success = False
1192
+
1193
+ if isinstance(right_type, OptionalTypeAnnotation):
1194
+ self.errors.append(
1195
+ Error(
1196
+ node.right.original_node,
1197
+ f"Expected the right operand to be a non-None, "
1198
+ f"but got: {right_type}",
1199
+ )
1200
+ )
1201
+ success = False
1202
+
1203
+ if not success:
1204
+ return None
1205
+
1206
+ result = PrimitiveTypeAnnotation(PrimitiveType.BOOL)
1207
+ self.type_map[node] = result
1208
+ return result
1209
+
1210
+ def transform_is_in(self, node: parse_tree.IsIn) -> Optional["TypeAnnotationUnion"]:
1211
+ # Just recurse to fill ``type_map`` on ``member`` and ``container`` even though
1212
+ # we know the type of the expression in advance.
1213
+
1214
+ member_type = self.transform(node.member)
1215
+ container_type = self.transform(node.container)
1216
+
1217
+ if member_type is None or container_type is None:
1218
+ return None
1219
+
1220
+ # NOTE (mristin, 2023-06-09):
1221
+ # Check that both the member and the container are non-nullables. We already
1222
+ # had bugs related to this, see:
1223
+ # https://github.com/aas-core-works/aas-core-meta/pull/272
1224
+ success = True
1225
+
1226
+ if isinstance(member_type, OptionalTypeAnnotation):
1227
+ self.errors.append(
1228
+ Error(
1229
+ node.member.original_node,
1230
+ f"Expected the member to be a non-None, but got: {member_type}",
1231
+ )
1232
+ )
1233
+ success = False
1234
+
1235
+ if isinstance(container_type, OptionalTypeAnnotation):
1236
+ self.errors.append(
1237
+ Error(
1238
+ node.container.original_node,
1239
+ f"Expected the container to be a non-None, "
1240
+ f"but got: {container_type}",
1241
+ )
1242
+ )
1243
+ success = False
1244
+
1245
+ if not success:
1246
+ return None
1247
+
1248
+ result = PrimitiveTypeAnnotation(PrimitiveType.BOOL)
1249
+ self.type_map[node] = result
1250
+ return result
1251
+
1252
+ def transform_implication(
1253
+ self, node: parse_tree.Implication
1254
+ ) -> Optional["TypeAnnotationUnion"]:
1255
+ # NOTE (mristin, 2022-06-17):
1256
+ # Just recurse to fill ``type_map`` on ``antecedent`` even though we know the
1257
+ # type in advance
1258
+
1259
+ antecedent_type = self.transform(node.antecedent)
1260
+ if antecedent_type is None:
1261
+ return None
1262
+
1263
+ success = True
1264
+
1265
+ if isinstance(antecedent_type, OptionalTypeAnnotation):
1266
+ self.errors.append(
1267
+ Error(
1268
+ node.antecedent.original_node,
1269
+ f"Expected the antecedent to be a non-None, "
1270
+ f"but got: {antecedent_type}",
1271
+ )
1272
+ )
1273
+ success = False
1274
+
1275
+ # region Recurse into consequent while considering any non-nullness
1276
+
1277
+ # NOTE (mristin, 2022-06-17):
1278
+ # We are very lax here and ignore the fact that calls to methods and functions
1279
+ # can actually alter the value assumed to be non-null, and actually violate
1280
+ # its non-nullness by setting it to null.
1281
+ #
1282
+ # This lack of conservatism works for now. If the bugs related to nullness
1283
+ # start to surface, we should re-think our approach here.
1284
+
1285
+ with contextlib.ExitStack() as exit_stack:
1286
+ if isinstance(node.antecedent, parse_tree.IsNotNone):
1287
+ canonical_repr = self._representation_map[node.antecedent.value]
1288
+ self._non_null.increment(canonical_repr)
1289
+
1290
+ exit_stack.callback(
1291
+ lambda a_canonical_repr=canonical_repr: self._non_null.decrement( # type: ignore
1292
+ a_canonical_repr
1293
+ )
1294
+ )
1295
+
1296
+ elif isinstance(node.antecedent, parse_tree.And):
1297
+ for value in node.antecedent.values:
1298
+ if isinstance(value, parse_tree.IsNotNone):
1299
+ canonical_repr = self._representation_map[value.value]
1300
+ self._non_null.increment(canonical_repr)
1301
+
1302
+ # fmt: off
1303
+ exit_stack.callback(
1304
+ lambda a_canonical_repr=canonical_repr: # type: ignore
1305
+ self._non_null.decrement(a_canonical_repr)
1306
+ )
1307
+ # fmt: on
1308
+ else:
1309
+ # NOTE (mristin, 2022-06-17):
1310
+ # We do not know how to infer any non-nullness in this case.
1311
+ pass
1312
+
1313
+ success = (self.transform(node.consequent) is not None) and success
1314
+
1315
+ if not success:
1316
+ return None
1317
+
1318
+ result = PrimitiveTypeAnnotation(PrimitiveType.BOOL)
1319
+ self.type_map[node] = result
1320
+ return result
1321
+
1322
+ def transform_method_call(
1323
+ self, node: parse_tree.MethodCall
1324
+ ) -> Optional["TypeAnnotationUnion"]:
1325
+ # Simply recurse to track the type, but we don't care about the arguments
1326
+ failed = False
1327
+ for arg in node.args:
1328
+ arg_type = self.transform(arg)
1329
+ if arg_type is None:
1330
+ failed = True
1331
+
1332
+ member_type = self.transform(node.member)
1333
+
1334
+ if member_type is None:
1335
+ failed = True
1336
+
1337
+ elif isinstance(member_type, OptionalTypeAnnotation):
1338
+ self.errors.append(
1339
+ Error(
1340
+ node.member.original_node,
1341
+ f"Expected the member to be a non-None, " f"but got: {member_type}",
1342
+ )
1343
+ )
1344
+ failed = True
1345
+ else:
1346
+ pass
1347
+
1348
+ if failed:
1349
+ return None
1350
+
1351
+ if not isinstance(member_type, MethodTypeAnnotation):
1352
+ self.errors.append(
1353
+ Error(
1354
+ node.original_node,
1355
+ f"Expected the member in a method call to be a method, "
1356
+ f"but got: {member_type}",
1357
+ )
1358
+ )
1359
+ return None
1360
+
1361
+ result: TypeAnnotationUnion
1362
+
1363
+ if member_type.method.returns is None:
1364
+ result = PrimitiveTypeAnnotation(a_type=PrimitiveType.NONE)
1365
+ else:
1366
+ result = convert_type_annotation(member_type.method.returns)
1367
+
1368
+ result = self._strip_optional_if_non_null(node=node, type_annotation=result)
1369
+ self.type_map[node] = result
1370
+ return result
1371
+
1372
+ def transform_function_call(
1373
+ self, node: parse_tree.FunctionCall
1374
+ ) -> Optional["TypeAnnotationUnion"]:
1375
+ result = None # type: Optional[TypeAnnotationUnion]
1376
+ failed = False
1377
+
1378
+ func_type = self.transform(node.name)
1379
+ if func_type is None:
1380
+ failed = True
1381
+ else:
1382
+ # NOTE (mristin, 2021-12-26):
1383
+ # The verification functions use
1384
+ # :py:mod:`aas_core_codegen.intermediate._types` while the built-in
1385
+ # functions are a construct of
1386
+ # :py:mod:`aas_core_codegen.intermediate.type_inference`.
1387
+
1388
+ if isinstance(func_type, VerificationTypeAnnotation):
1389
+ if func_type.func.returns is not None:
1390
+ result = convert_type_annotation(func_type.func.returns)
1391
+ else:
1392
+ result = PrimitiveTypeAnnotation(PrimitiveType.NONE)
1393
+
1394
+ elif isinstance(func_type, BuiltinFunctionTypeAnnotation):
1395
+ if func_type.func.returns is not None:
1396
+ result = func_type.func.returns
1397
+ else:
1398
+ result = PrimitiveTypeAnnotation(PrimitiveType.NONE)
1399
+
1400
+ elif isinstance(
1401
+ func_type,
1402
+ (
1403
+ PrimitiveTypeAnnotation,
1404
+ OurTypeAnnotation,
1405
+ MethodTypeAnnotation,
1406
+ ListTypeAnnotation,
1407
+ SetTypeAnnotation,
1408
+ OptionalTypeAnnotation,
1409
+ EnumerationAsTypeTypeAnnotation,
1410
+ ),
1411
+ ):
1412
+ self.errors.append(
1413
+ Error(
1414
+ node.name.original_node,
1415
+ f"Expected the variable {node.name.identifier!r} to be "
1416
+ f"a function, but got {func_type}",
1417
+ )
1418
+ )
1419
+
1420
+ else:
1421
+ assert_never(func_type)
1422
+
1423
+ # NOTE (mristin, 2021-12-26):
1424
+ # Recurse to track the type of arguments. Even if we failed before, we want to
1425
+ # catch the errors in the arguments for better developer experience.
1426
+ #
1427
+ # Mind that we are sloppy here. Theoretically, we could check that arguments in
1428
+ # the call are assignable to the arguments in the function definition and catch
1429
+ # errors in the meta-model at this point. However, we prioritize other features
1430
+ # and leave this check unimplemented for now.
1431
+
1432
+ for arg in node.args:
1433
+ arg_type = self.transform(arg)
1434
+ if arg_type is None:
1435
+ failed = True
1436
+
1437
+ if failed:
1438
+ return None
1439
+
1440
+ assert result is not None
1441
+
1442
+ result = self._strip_optional_if_non_null(node=node, type_annotation=result)
1443
+ self.type_map[node] = result
1444
+ return result
1445
+
1446
+ def transform_constant(
1447
+ self, node: parse_tree.Constant
1448
+ ) -> Optional["TypeAnnotationUnion"]:
1449
+ result: TypeAnnotationUnion
1450
+
1451
+ if isinstance(node.value, bool):
1452
+ result = PrimitiveTypeAnnotation(PrimitiveType.BOOL)
1453
+ elif isinstance(node.value, int):
1454
+ result = PrimitiveTypeAnnotation(PrimitiveType.INT)
1455
+ elif isinstance(node.value, float):
1456
+ result = PrimitiveTypeAnnotation(PrimitiveType.FLOAT)
1457
+ elif isinstance(node.value, str):
1458
+ result = PrimitiveTypeAnnotation(PrimitiveType.STR)
1459
+ else:
1460
+ assert_never(node.value)
1461
+
1462
+ self.type_map[node] = result
1463
+ return result
1464
+
1465
+ def transform_is_none(
1466
+ self, node: parse_tree.IsNone
1467
+ ) -> Optional["TypeAnnotationUnion"]:
1468
+ value_type = self.transform(node.value)
1469
+
1470
+ # NOTE (mristin):
1471
+ # Something went wrong if we could not infer the type of the ``value``.
1472
+ if value_type is None:
1473
+ return None
1474
+
1475
+ if not isinstance(value_type, OptionalTypeAnnotation):
1476
+ self.errors.append(
1477
+ Error(
1478
+ node.value.original_node,
1479
+ f"Expected the value to be of an optional type for "
1480
+ f"a nullness check (``is None``), "
1481
+ f"but got {value_type}",
1482
+ )
1483
+ )
1484
+ return None
1485
+
1486
+ result = PrimitiveTypeAnnotation(PrimitiveType.BOOL)
1487
+ self.type_map[node] = result
1488
+ return result
1489
+
1490
+ def transform_is_not_none(
1491
+ self, node: parse_tree.IsNotNone
1492
+ ) -> Optional["TypeAnnotationUnion"]:
1493
+ value_type = self.transform(node.value)
1494
+
1495
+ # NOTE (mristin):
1496
+ # Something went wrong if we could not infer the type of the ``value``.
1497
+ if value_type is None:
1498
+ return None
1499
+
1500
+ if not isinstance(value_type, OptionalTypeAnnotation):
1501
+ self.errors.append(
1502
+ Error(
1503
+ node.value.original_node,
1504
+ f"Expected the value to be of an optional type "
1505
+ f"for a non-nullness check (``is not None``), "
1506
+ f"but got {value_type}",
1507
+ )
1508
+ )
1509
+ return None
1510
+
1511
+ result = PrimitiveTypeAnnotation(PrimitiveType.BOOL)
1512
+ self.type_map[node] = result
1513
+ return result
1514
+
1515
+ def transform_not(self, node: parse_tree.Not) -> Optional["TypeAnnotationUnion"]:
1516
+ # Just recurse to fill ``type_map`` on ``operand`` even though we know the type
1517
+ # in advance
1518
+
1519
+ operand_type = self.transform(node.operand)
1520
+
1521
+ if operand_type is None:
1522
+ return None
1523
+
1524
+ if isinstance(operand_type, OptionalTypeAnnotation):
1525
+ self.errors.append(
1526
+ Error(
1527
+ node.operand.original_node,
1528
+ f"Expected the operand to be a non-None, "
1529
+ f"but got: {operand_type}",
1530
+ )
1531
+ )
1532
+ return None
1533
+
1534
+ result = PrimitiveTypeAnnotation(PrimitiveType.BOOL)
1535
+ self.type_map[node] = result
1536
+ return result
1537
+
1538
+ def transform_name(self, node: parse_tree.Name) -> Optional["TypeAnnotationUnion"]:
1539
+ type_in_env = self._environment.find(node.identifier)
1540
+ if type_in_env is None:
1541
+ self.errors.append(
1542
+ Error(
1543
+ node.original_node,
1544
+ f"We do not know how to infer the type of "
1545
+ f"the variable with the identifier {node.identifier!r} from the "
1546
+ f"given environment. Mind that we do not consider the module "
1547
+ f"scope nor handle all built-in functions due to simplicity! If "
1548
+ f"you believe this needs to work, please notify the developers.",
1549
+ )
1550
+ )
1551
+ return None
1552
+
1553
+ result = type_in_env
1554
+
1555
+ result = self._strip_optional_if_non_null(node=node, type_annotation=result)
1556
+ self.type_map[node] = result
1557
+ return result
1558
+
1559
+ def transform_and(self, node: parse_tree.And) -> Optional["TypeAnnotationUnion"]:
1560
+ # NOTE (mristin, 2022-06-17):
1561
+ # We need to iterate and recurse into ``values`` to fill the ``type_map``.
1562
+ # In the process, we have to consider the non-nullness and how it applies
1563
+ # to the remainder of the conjunction.
1564
+
1565
+ # NOTE (mristin, 2022-06-17):
1566
+ # We are very lax here and ignore the fact that calls to methods and functions
1567
+ # can actually alter the value assumed to be non-null, and actually violate
1568
+ # its non-nullness by setting it to null.
1569
+ #
1570
+ # This lack of conservatism works for now. If the bugs related to nullness
1571
+ # start to surface, we should re-think our approach here.
1572
+
1573
+ success = True
1574
+
1575
+ with contextlib.ExitStack() as exit_stack:
1576
+ for value_node in node.values:
1577
+ value_type = self.transform(value_node)
1578
+ if value_type is None:
1579
+ return None
1580
+
1581
+ if isinstance(value_type, OptionalTypeAnnotation):
1582
+ self.errors.append(
1583
+ Error(
1584
+ value_node.original_node,
1585
+ f"Expected the value to be a non-None, "
1586
+ f"but got: {value_type}",
1587
+ )
1588
+ )
1589
+ success = False
1590
+
1591
+ if isinstance(value_node, parse_tree.IsNotNone):
1592
+ canonical_repr = self._representation_map[value_node.value]
1593
+ self._non_null.increment(canonical_repr)
1594
+
1595
+ # fmt: off
1596
+ exit_stack.callback(
1597
+ lambda a_canonical_repr=canonical_repr: # type: ignore
1598
+ self._non_null.decrement(a_canonical_repr)
1599
+ )
1600
+ # fmt: on
1601
+
1602
+ if not success:
1603
+ return None
1604
+
1605
+ result = PrimitiveTypeAnnotation(PrimitiveType.BOOL)
1606
+ self.type_map[node] = result
1607
+ return result
1608
+
1609
+ def transform_or(self, node: parse_tree.Or) -> Optional["TypeAnnotationUnion"]:
1610
+ # Just recurse to fill ``type_map`` on ``values`` even though we know the type
1611
+ # in advance
1612
+
1613
+ success = True
1614
+
1615
+ with contextlib.ExitStack() as exit_stack:
1616
+ for value_node in node.values:
1617
+ value_type = self.transform(value_node)
1618
+ if value_type is None:
1619
+ return None
1620
+
1621
+ if isinstance(value_type, OptionalTypeAnnotation):
1622
+ self.errors.append(
1623
+ Error(
1624
+ value_node.original_node,
1625
+ f"Expected the value to be a non-None, "
1626
+ f"but got: {value_type}",
1627
+ )
1628
+ )
1629
+ success = False
1630
+
1631
+ if isinstance(value_node, parse_tree.IsNone):
1632
+ canonical_repr = self._representation_map[value_node.value]
1633
+ self._non_null.increment(canonical_repr)
1634
+
1635
+ # fmt: off
1636
+ exit_stack.callback(
1637
+ lambda a_canonical_repr=canonical_repr: # type: ignore
1638
+ self._non_null.decrement(
1639
+ a_canonical_repr
1640
+ )
1641
+ )
1642
+ # fmt: on
1643
+
1644
+ if not success:
1645
+ return None
1646
+
1647
+ result = PrimitiveTypeAnnotation(PrimitiveType.BOOL)
1648
+ self.type_map[node] = result
1649
+ return result
1650
+
1651
+ @staticmethod
1652
+ def _binary_operation_name_with_capital_the(
1653
+ node: Union[parse_tree.Add, parse_tree.Sub]
1654
+ ) -> str:
1655
+ if isinstance(node, parse_tree.Add):
1656
+ return "The addition"
1657
+
1658
+ elif isinstance(node, parse_tree.Sub):
1659
+ return "The subtraction"
1660
+
1661
+ else:
1662
+ assert_never(node)
1663
+
1664
+ def _transform_add_or_sub(
1665
+ self, node: Union[parse_tree.Add, parse_tree.Sub]
1666
+ ) -> Optional["TypeAnnotationUnion"]:
1667
+ left_type = self.transform(node.left)
1668
+ if left_type is None:
1669
+ return None
1670
+
1671
+ right_type = self.transform(node.right)
1672
+ if right_type is None:
1673
+ return None
1674
+
1675
+ success = True
1676
+
1677
+ if isinstance(left_type, OptionalTypeAnnotation):
1678
+ self.errors.append(
1679
+ Error(
1680
+ node.left.original_node,
1681
+ f"Expected the left operand to be a non-None, "
1682
+ f"but got: {left_type}",
1683
+ )
1684
+ )
1685
+ success = False
1686
+
1687
+ if isinstance(right_type, OptionalTypeAnnotation):
1688
+ self.errors.append(
1689
+ Error(
1690
+ node.right.original_node,
1691
+ f"Expected the right operand to be a non-None, "
1692
+ f"but got: {right_type}",
1693
+ )
1694
+ )
1695
+ success = False
1696
+
1697
+ if not success:
1698
+ return None
1699
+
1700
+ if not (
1701
+ isinstance(left_type, PrimitiveTypeAnnotation)
1702
+ and left_type.a_type
1703
+ in (
1704
+ PrimitiveType.INT,
1705
+ PrimitiveType.FLOAT,
1706
+ PrimitiveType.LENGTH,
1707
+ )
1708
+ ):
1709
+ self.errors.append(
1710
+ Error(
1711
+ node.left.original_node,
1712
+ f"{_Inferrer._binary_operation_name_with_capital_the(node)} is "
1713
+ f"only defined on integer and floating-point numbers, "
1714
+ f"but got as a left operand: {left_type}",
1715
+ )
1716
+ )
1717
+ success = False
1718
+
1719
+ if not (
1720
+ isinstance(right_type, PrimitiveTypeAnnotation)
1721
+ and right_type.a_type
1722
+ in (
1723
+ PrimitiveType.INT,
1724
+ PrimitiveType.FLOAT,
1725
+ PrimitiveType.LENGTH,
1726
+ )
1727
+ ):
1728
+ self.errors.append(
1729
+ Error(
1730
+ node.right.original_node,
1731
+ f"{_Inferrer._binary_operation_name_with_capital_the(node)} is "
1732
+ f"only defined on integer and floating-point numbers, "
1733
+ f"but got as a right operand: {right_type}",
1734
+ )
1735
+ )
1736
+ success = False
1737
+
1738
+ if not success:
1739
+ return None
1740
+
1741
+ assert isinstance(left_type, PrimitiveTypeAnnotation)
1742
+ assert isinstance(right_type, PrimitiveTypeAnnotation)
1743
+
1744
+ # fmt: off
1745
+ if (
1746
+ (
1747
+ left_type.a_type is PrimitiveType.FLOAT
1748
+ and right_type.a_type is not PrimitiveType.FLOAT
1749
+ ) or (
1750
+ right_type.a_type is PrimitiveType.FLOAT
1751
+ and left_type.a_type is not PrimitiveType.FLOAT
1752
+ )
1753
+ ):
1754
+ # fmt: on
1755
+ self.errors.append(
1756
+ Error(
1757
+ node.original_node,
1758
+ f"You can not mix floating-point and integer numbers, "
1759
+ f"but the left operand was: {left_type}; "
1760
+ f"and the right operand was: {right_type}"
1761
+ )
1762
+ )
1763
+ success = False
1764
+
1765
+ if not success:
1766
+ return None
1767
+
1768
+ # fmt: off
1769
+ result_type: PrimitiveType
1770
+ if (
1771
+ (
1772
+ left_type.a_type is PrimitiveType.LENGTH
1773
+ and right_type.a_type in (PrimitiveType.INT, PrimitiveType.LENGTH)
1774
+ ) or (
1775
+ right_type.a_type is PrimitiveType.LENGTH
1776
+ and left_type.a_type in (PrimitiveType.INT, PrimitiveType.LENGTH)
1777
+ )
1778
+ ):
1779
+ result_type = PrimitiveType.LENGTH
1780
+
1781
+ elif (
1782
+ left_type.a_type is PrimitiveType.INT
1783
+ and right_type.a_type is PrimitiveType.INT
1784
+ ):
1785
+ result_type = PrimitiveType.INT
1786
+
1787
+ elif (
1788
+ left_type.a_type is PrimitiveType.FLOAT
1789
+ and right_type.a_type is PrimitiveType.FLOAT
1790
+ ):
1791
+ result_type = PrimitiveType.FLOAT
1792
+ else:
1793
+ raise AssertionError(
1794
+ f"Unhandled execution path: {left_type=}, {right_type=}"
1795
+ )
1796
+ # fmt: on
1797
+
1798
+ result = PrimitiveTypeAnnotation(a_type=result_type)
1799
+ self.type_map[node] = result
1800
+ return result
1801
+
1802
+ def transform_add(self, node: parse_tree.Add) -> Optional["TypeAnnotationUnion"]:
1803
+ return self._transform_add_or_sub(node)
1804
+
1805
+ def transform_sub(self, node: parse_tree.Sub) -> Optional["TypeAnnotationUnion"]:
1806
+ return self._transform_add_or_sub(node)
1807
+
1808
+ def transform_formatted_value(
1809
+ self, node: parse_tree.FormattedValue
1810
+ ) -> Optional["TypeAnnotationUnion"]:
1811
+ value_type = self.transform(node.value)
1812
+ if value_type is None:
1813
+ return None
1814
+
1815
+ if isinstance(value_type, OptionalTypeAnnotation):
1816
+ self.errors.append(
1817
+ Error(
1818
+ node.value.original_node,
1819
+ f"Expected the value to be a non-None, " f"but got: {value_type}",
1820
+ )
1821
+ )
1822
+ return None
1823
+
1824
+ result = PrimitiveTypeAnnotation(PrimitiveType.STR)
1825
+ self.type_map[node] = result
1826
+ return result
1827
+
1828
+ def transform_joined_str(
1829
+ self, node: parse_tree.JoinedStr
1830
+ ) -> Optional["TypeAnnotationUnion"]:
1831
+ # Just recurse to fill ``type_map`` on ``values`` even though we know the type
1832
+ # in advance
1833
+ success = True
1834
+ for value in node.values:
1835
+ if isinstance(value, str):
1836
+ continue
1837
+ elif isinstance(value, parse_tree.FormattedValue):
1838
+ formatted_value_type = self.transform(value)
1839
+ if formatted_value_type is None:
1840
+ success = False
1841
+ else:
1842
+ assert_never(value)
1843
+
1844
+ if not success:
1845
+ return None
1846
+
1847
+ result = PrimitiveTypeAnnotation(PrimitiveType.STR)
1848
+ self.type_map[node] = result
1849
+ return result
1850
+
1851
+ def transform_for_each(
1852
+ self, node: parse_tree.ForEach
1853
+ ) -> Optional["TypeAnnotationUnion"]:
1854
+ variable_type_in_env = self._environment.find(node.variable.identifier)
1855
+ if variable_type_in_env is not None:
1856
+ self.errors.append(
1857
+ Error(
1858
+ node.variable.original_node,
1859
+ f"The variable {node.variable.identifier} "
1860
+ f"has been already defined before",
1861
+ )
1862
+ )
1863
+ return None
1864
+
1865
+ iter_type = self.transform(node.iteration)
1866
+ if iter_type is None:
1867
+ return None
1868
+
1869
+ if isinstance(iter_type, OptionalTypeAnnotation):
1870
+ self.errors.append(
1871
+ Error(
1872
+ node.iteration.original_node,
1873
+ f"Expected the collection which we iterate over to be a non-None, "
1874
+ f"but got: {iter_type}",
1875
+ )
1876
+ )
1877
+ return None
1878
+
1879
+ if not isinstance(iter_type, ListTypeAnnotation):
1880
+ self.errors.append(
1881
+ Error(
1882
+ node.iteration.original_node,
1883
+ f"Expected an iteration over a list, but got: {iter_type}",
1884
+ )
1885
+ )
1886
+ return None
1887
+
1888
+ loop_variable_type = iter_type.items
1889
+
1890
+ self.type_map[node.variable] = loop_variable_type
1891
+
1892
+ result = PrimitiveTypeAnnotation(PrimitiveType.NONE)
1893
+ self.type_map[node] = result
1894
+ return result
1895
+
1896
+ def transform_for_range(
1897
+ self, node: parse_tree.ForRange
1898
+ ) -> Optional["TypeAnnotationUnion"]:
1899
+ variable_type_in_env = self._environment.find(node.variable.identifier)
1900
+ if variable_type_in_env is not None:
1901
+ self.errors.append(
1902
+ Error(
1903
+ node.variable.original_node,
1904
+ f"The variable {node.variable.identifier} "
1905
+ f"has been already defined before",
1906
+ )
1907
+ )
1908
+ return None
1909
+
1910
+ start_type = self.transform(node.start)
1911
+ if start_type is None:
1912
+ return None
1913
+
1914
+ end_type = self.transform(node.end)
1915
+ if end_type is None:
1916
+ return None
1917
+
1918
+ success = True
1919
+
1920
+ if isinstance(start_type, OptionalTypeAnnotation):
1921
+ self.errors.append(
1922
+ Error(
1923
+ node.start.original_node,
1924
+ f"Expected the start to be a non-None, " f"but got: {start_type}",
1925
+ )
1926
+ )
1927
+ success = False
1928
+
1929
+ if isinstance(end_type, OptionalTypeAnnotation):
1930
+ self.errors.append(
1931
+ Error(
1932
+ node.end.original_node,
1933
+ f"Expected the end to be a non-None, " f"but got: {end_type}",
1934
+ )
1935
+ )
1936
+ success = False
1937
+
1938
+ if not success:
1939
+ return None
1940
+
1941
+ if not (
1942
+ isinstance(start_type, PrimitiveTypeAnnotation)
1943
+ and start_type.a_type in (PrimitiveType.INT, PrimitiveType.LENGTH)
1944
+ ):
1945
+ self.errors.append(
1946
+ Error(
1947
+ node.start.original_node,
1948
+ f"Expected the start of a range to be an integer, "
1949
+ f"but got: {start_type}",
1950
+ )
1951
+ )
1952
+ return None
1953
+
1954
+ if not (
1955
+ isinstance(end_type, PrimitiveTypeAnnotation)
1956
+ and end_type.a_type in (PrimitiveType.INT, PrimitiveType.LENGTH)
1957
+ ):
1958
+ self.errors.append(
1959
+ Error(
1960
+ node.end.original_node,
1961
+ f"Expected the end of a range to be an integer, "
1962
+ f"but got: {end_type}",
1963
+ )
1964
+ )
1965
+ return None
1966
+
1967
+ # region Pick the larger integer type for the type of the loop variable
1968
+ assert isinstance(
1969
+ start_type, PrimitiveTypeAnnotation
1970
+ ) and start_type.a_type in (PrimitiveType.INT, PrimitiveType.LENGTH)
1971
+ assert isinstance(end_type, PrimitiveTypeAnnotation) and end_type.a_type in (
1972
+ PrimitiveType.INT,
1973
+ PrimitiveType.LENGTH,
1974
+ )
1975
+
1976
+ loop_variable_type: PrimitiveTypeAnnotation
1977
+ if (
1978
+ start_type.a_type is PrimitiveType.LENGTH
1979
+ or end_type.a_type is PrimitiveType.LENGTH
1980
+ ):
1981
+ loop_variable_type = PrimitiveTypeAnnotation(a_type=PrimitiveType.LENGTH)
1982
+ else:
1983
+ assert (
1984
+ start_type.a_type is PrimitiveType.INT
1985
+ and end_type.a_type is PrimitiveType.INT
1986
+ )
1987
+ loop_variable_type = PrimitiveTypeAnnotation(a_type=PrimitiveType.INT)
1988
+
1989
+ # endregion
1990
+
1991
+ self.type_map[node.variable] = loop_variable_type
1992
+
1993
+ result = PrimitiveTypeAnnotation(PrimitiveType.NONE)
1994
+ self.type_map[node] = result
1995
+ return result
1996
+
1997
+ def _transform_any_or_all(
1998
+ self, node: Union[parse_tree.Any, parse_tree.All]
1999
+ ) -> Optional["TypeAnnotationUnion"]:
2000
+ a_type = self.transform(node.generator)
2001
+ if a_type is None:
2002
+ return None
2003
+
2004
+ loop_variable_type = self.type_map[node.generator.variable]
2005
+ try:
2006
+ self._environment.set(
2007
+ identifier=node.generator.variable.identifier,
2008
+ type_annotation=loop_variable_type,
2009
+ )
2010
+
2011
+ a_type = self.transform(node.condition)
2012
+ if a_type is None:
2013
+ return None
2014
+
2015
+ if (
2016
+ not isinstance(a_type, PrimitiveTypeAnnotation)
2017
+ or a_type.a_type is not PrimitiveType.BOOL
2018
+ ):
2019
+ self.errors.append(
2020
+ Error(
2021
+ node.condition.original_node,
2022
+ f"Expected the condition to be a boolean, "
2023
+ f"but got: {a_type}",
2024
+ )
2025
+ )
2026
+ return None
2027
+
2028
+ finally:
2029
+ self._environment.remove(identifier=node.generator.variable.identifier)
2030
+
2031
+ result = PrimitiveTypeAnnotation(PrimitiveType.BOOL)
2032
+ self.type_map[node] = result
2033
+ return result
2034
+
2035
+ def transform_any(self, node: parse_tree.Any) -> Optional["TypeAnnotationUnion"]:
2036
+ return self._transform_any_or_all(node)
2037
+
2038
+ def transform_all(self, node: parse_tree.All) -> Optional["TypeAnnotationUnion"]:
2039
+ return self._transform_any_or_all(node)
2040
+
2041
+ def transform_assignment(
2042
+ self, node: parse_tree.Assignment
2043
+ ) -> Optional["TypeAnnotationUnion"]:
2044
+ is_new_variable = False
2045
+
2046
+ target_type: Optional[TypeAnnotationUnion]
2047
+
2048
+ if isinstance(node.target, parse_tree.Name):
2049
+ target_type = self._environment.find(node.target.identifier)
2050
+ if target_type is None:
2051
+ is_new_variable = True
2052
+ else:
2053
+ target_type = self.transform(node.target)
2054
+
2055
+ value_type = self.transform(node.value)
2056
+
2057
+ if (not is_new_variable and target_type is None) or (value_type is None):
2058
+ return None
2059
+
2060
+ if target_type is not None and not _assignable(
2061
+ target_type=target_type, value_type=value_type
2062
+ ):
2063
+ self.errors.append(
2064
+ Error(
2065
+ node.original_node,
2066
+ f"We inferred the target type of the assignment to "
2067
+ f"be {target_type}, while the value type is inferred to "
2068
+ f"be {value_type}. We do not know how to model this assignment.",
2069
+ )
2070
+ )
2071
+ return None
2072
+
2073
+ if is_new_variable:
2074
+ assert isinstance(node.target, parse_tree.Name)
2075
+
2076
+ self._environment.set(
2077
+ identifier=node.target.identifier, type_annotation=value_type
2078
+ )
2079
+
2080
+ result = PrimitiveTypeAnnotation(PrimitiveType.NONE)
2081
+ self.type_map[node] = result
2082
+ return result
2083
+
2084
+ def transform_return(
2085
+ self, node: parse_tree.Return
2086
+ ) -> Optional["TypeAnnotationUnion"]:
2087
+ # Just recurse to fill ``type_map`` on ``value`` even though we know the type
2088
+ # in advance
2089
+ if node.value is not None:
2090
+ success = self.transform(node.value) is not None
2091
+ if not success:
2092
+ return None
2093
+
2094
+ # Treat ``return`` as a statement
2095
+ result = PrimitiveTypeAnnotation(PrimitiveType.NONE)
2096
+ self.type_map[node] = result
2097
+ return result
2098
+
2099
+
2100
+ def populate_base_environment(symbol_table: _types.SymbolTable) -> Environment:
2101
+ """Create a basic mapping name 🠒 type annotation from the global scope.
2102
+
2103
+ The global scope, in this context, refers to the level of symbol table.
2104
+ """
2105
+ # Build up the environment;
2106
+ # see https://craftinginterpreters.com/resolving-and-binding.html
2107
+ mapping: MutableMapping[Identifier, "TypeAnnotationUnion"] = {
2108
+ Identifier("len"): BuiltinFunctionTypeAnnotation(
2109
+ func=BuiltinFunction(
2110
+ name=Identifier("len"),
2111
+ returns=PrimitiveTypeAnnotation(PrimitiveType.LENGTH),
2112
+ )
2113
+ )
2114
+ }
2115
+
2116
+ for constant in symbol_table.constants:
2117
+ if isinstance(constant, _types.ConstantPrimitive):
2118
+ mapping[constant.name] = PrimitiveTypeAnnotation(
2119
+ a_type=PRIMITIVE_TYPE_MAP[constant.a_type]
2120
+ )
2121
+ elif isinstance(constant, _types.ConstantSetOfPrimitives):
2122
+ mapping[constant.name] = SetTypeAnnotation(
2123
+ items=PrimitiveTypeAnnotation(PRIMITIVE_TYPE_MAP[constant.a_type])
2124
+ )
2125
+ elif isinstance(constant, _types.ConstantSetOfEnumerationLiterals):
2126
+ mapping[constant.name] = SetTypeAnnotation(
2127
+ items=OurTypeAnnotation(our_type=constant.enumeration)
2128
+ )
2129
+ else:
2130
+ assert_never(constant)
2131
+
2132
+ for verification in symbol_table.verification_functions:
2133
+ assert verification.name not in mapping
2134
+ mapping[verification.name] = VerificationTypeAnnotation(func=verification)
2135
+
2136
+ for our_type in symbol_table.our_types:
2137
+ if isinstance(our_type, _types.Enumeration):
2138
+ assert our_type.name not in mapping
2139
+ mapping[our_type.name] = EnumerationAsTypeTypeAnnotation(
2140
+ enumeration=our_type
2141
+ )
2142
+
2143
+ return ImmutableEnvironment(mapping=mapping, parent=None)
2144
+
2145
+
2146
+ class InferenceOfFunction:
2147
+ """Represent the result of type inference on a function body and arguments."""
2148
+
2149
+ #: Environment inferred after processing a body of statements including
2150
+ #: the function arguments
2151
+ environment_with_args: Final[Environment]
2152
+
2153
+ #: Map of body nodes to types
2154
+ type_map: Final[Mapping[parse_tree.Node, "TypeAnnotationUnion"]]
2155
+
2156
+ def __init__(
2157
+ self,
2158
+ environment_with_args: Environment,
2159
+ type_map: Mapping[parse_tree.Node, "TypeAnnotationUnion"],
2160
+ ) -> None:
2161
+ """Initialize with the given values."""
2162
+ self.environment_with_args = environment_with_args
2163
+ self.type_map = type_map
2164
+
2165
+
2166
+ @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
2167
+ def infer_for_verification(
2168
+ verification: _types.TranspilableVerification, base_environment: Environment
2169
+ ) -> Tuple[Optional[InferenceOfFunction], Optional[Error]]:
2170
+ """Infer the types for the given function and map the body nodes to the types."""
2171
+ canonicalizer = _Canonicalizer()
2172
+ for node in verification.parsed.body:
2173
+ _ = canonicalizer.transform(node)
2174
+
2175
+ environment = MutableEnvironment(parent=base_environment)
2176
+
2177
+ for arg in verification.arguments:
2178
+ environment.set(
2179
+ identifier=arg.name,
2180
+ type_annotation=convert_type_annotation(arg.type_annotation),
2181
+ )
2182
+
2183
+ type_inferrer = _Inferrer(
2184
+ environment=environment,
2185
+ representation_map=canonicalizer.representation_map,
2186
+ )
2187
+
2188
+ for node in verification.parsed.body:
2189
+ _ = type_inferrer.transform(node)
2190
+
2191
+ if len(type_inferrer.errors):
2192
+ return None, Error(
2193
+ verification.parsed.node,
2194
+ f"Failed to infer the types "
2195
+ f"in the verification function {verification.name!r}",
2196
+ type_inferrer.errors,
2197
+ )
2198
+
2199
+ return (
2200
+ InferenceOfFunction(
2201
+ environment_with_args=environment, type_map=type_inferrer.type_map
2202
+ ),
2203
+ None,
2204
+ )
2205
+
2206
+
2207
+ @ensure(lambda result: (result[0] is not None) ^ (result[1] is not None))
2208
+ def infer_for_invariant(
2209
+ invariant: _types.Invariant, environment: Environment
2210
+ ) -> Tuple[Optional[Mapping[parse_tree.Node, "TypeAnnotationUnion"]], Optional[Error]]:
2211
+ """Infer the types of the nodes corresponding to the body of an invariant."""
2212
+ canonicalizer = _Canonicalizer()
2213
+ _ = canonicalizer.transform(invariant.body)
2214
+
2215
+ type_inferrer = _Inferrer(
2216
+ environment=environment,
2217
+ representation_map=canonicalizer.representation_map,
2218
+ )
2219
+
2220
+ _ = type_inferrer.transform(invariant.body)
2221
+
2222
+ if len(type_inferrer.errors):
2223
+ return None, Error(
2224
+ invariant.parsed.node,
2225
+ "Failed to infer the types in the invariant",
2226
+ type_inferrer.errors,
2227
+ )
2228
+
2229
+ return type_inferrer.type_map, None
2230
+
2231
+
2232
+ assert_union_of_descendants_exhaustive(
2233
+ union=TypeAnnotationUnion, base_class=TypeAnnotation
2234
+ )
2235
+
2236
+ TypeAnnotationExceptOptional = Union[
2237
+ PrimitiveTypeAnnotation,
2238
+ OurTypeAnnotation,
2239
+ VerificationTypeAnnotation,
2240
+ BuiltinFunctionTypeAnnotation,
2241
+ MethodTypeAnnotation,
2242
+ ListTypeAnnotation,
2243
+ SetTypeAnnotation,
2244
+ EnumerationAsTypeTypeAnnotation,
2245
+ ]
2246
+ assert_union_without_excluded(
2247
+ original_union=TypeAnnotationUnion,
2248
+ subset_union=TypeAnnotationExceptOptional,
2249
+ excluded=[OptionalTypeAnnotation],
2250
+ )
2251
+
2252
+ FunctionTypeAnnotationUnion = Union[
2253
+ VerificationTypeAnnotation, BuiltinFunctionTypeAnnotation
2254
+ ]
2255
+ assert_union_of_descendants_exhaustive(
2256
+ union=FunctionTypeAnnotationUnion, base_class=FunctionTypeAnnotation
2257
+ )
2258
+
2259
+ # NOTE (mristin, 2021-12-27):
2260
+ # Mypy is not smart enough to work with ``get_args``, so we have to manually write it
2261
+ # out.
2262
+ FunctionTypeAnnotationUnionAsTuple = (
2263
+ VerificationTypeAnnotation,
2264
+ BuiltinFunctionTypeAnnotation,
2265
+ )
2266
+ assert FunctionTypeAnnotationUnionAsTuple == get_args(FunctionTypeAnnotationUnion)