expressir 2.4.29-arm-linux

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 (426) hide show
  1. checksums.yaml +7 -0
  2. data/.cargo/config.toml +3 -0
  3. data/.github/scripts/test_installed_gem.rb +34 -0
  4. data/.github/workflows/codeql.yml +35 -0
  5. data/.github/workflows/docs.yml +99 -0
  6. data/.github/workflows/links.yml +100 -0
  7. data/.github/workflows/native-gems.yml +201 -0
  8. data/.github/workflows/rake.yml +19 -0
  9. data/.github/workflows/release.yml +37 -0
  10. data/.github/workflows/rust-ext.yml +41 -0
  11. data/.github/workflows/stress.yml +36 -0
  12. data/.github/workflows/validate_schemas.yml +48 -0
  13. data/.github/workflows/verify_remarks.yml +33 -0
  14. data/.gitignore +55 -0
  15. data/.hound.yml +3 -0
  16. data/.rspec +2 -0
  17. data/.rubocop.yml +18 -0
  18. data/.rubocop_todo.yml +297 -0
  19. data/CHANGELOG.md +159 -0
  20. data/Gemfile +18 -0
  21. data/README.adoc +2783 -0
  22. data/Rakefile +41 -0
  23. data/TODO.bugs/01-stale-transformer-autoload.md +39 -0
  24. data/TODO.bugs/02-parser-class-instance-vars.md +36 -0
  25. data/TODO.bugs/03-builder-mutable-state.md +43 -0
  26. data/TODO.bugs/04-formatter-public-send-dispatch.md +53 -0
  27. data/TODO.bugs/05-anonymous-formatter-subclass.md +45 -0
  28. data/TODO.bugs/06-collection-registry-single-source.md +53 -0
  29. data/TODO.bugs/07-require-relative-cleanup.md +42 -0
  30. data/TODO.bugs/08-require-expressir-in-commands.md +34 -0
  31. data/TODO.bugs/09-parser-split.md +53 -0
  32. data/TODO.bugs/10-to-s-override.md +42 -0
  33. data/TODO.bugs/11-parser-class-variables.md +39 -0
  34. data/TODO.bugs/12-marker-modules-vs-registry.md +64 -0
  35. data/TODO.bugs/13-string-literal-scanner-limitation.md +52 -0
  36. data/TODO.bugs/14-model-formatting-leak.md +30 -0
  37. data/TODO.bugs/15-expression-children-macro.md +27 -0
  38. data/TODO.bugs/16-pretty-formatter-duplication.md +28 -0
  39. data/TODO.bugs/17-snake-case-cache-mutable-constant.md +28 -0
  40. data/TODO.bugs/18-const-get-private-constants.md +30 -0
  41. data/TODO.bugs/19-format-methods-public.md +22 -0
  42. data/TODO.bugs/20-coverage-nested-entities-dedup.md +20 -0
  43. data/TODO.bugs/21-operator-tokens-secondary-dispatch.md +21 -0
  44. data/TODO.bugs/22-builder-fast-path-wrappers.md +32 -0
  45. data/TODO.bugs/23-coverage-inverse-maps.md +21 -0
  46. data/TODO.bugs/24-streaming-builder-complexity.md +19 -0
  47. data/TODO.bugs/25-debug-puts-in-production.md +21 -0
  48. data/TODO.bugs/26-generic-entity-children-misplaced.md +21 -0
  49. data/TODO.bugs/27-package-build-god-method.md +19 -0
  50. data/TODO.bugs/28-package-god-class.md +30 -0
  51. data/TODO.bugs/29-validate-ascii-god-class.md +24 -0
  52. data/TODO.bugs/30-unicode-map-extraction.md +19 -0
  53. data/TODO.bugs/README.md +43 -0
  54. data/TODO.max-perf/01-restore-ci-green.md +36 -0
  55. data/TODO.max-perf/02-streaming-parse-path.md +31 -0
  56. data/TODO.max-perf/03-cli-parallel-opt-in.md +27 -0
  57. data/TODO.max-perf/04-benchmark-harness.md +28 -0
  58. data/TODO.max-perf/05-parallel-fidelity-specs.md +22 -0
  59. data/TODO.max-perf/06-builder-cpu-audit.md +41 -0
  60. data/TODO.max-perf/07-upstream-parsanol-roadmap.md +27 -0
  61. data/TODO.max-perf/08-builder-build-perf.md +45 -0
  62. data/TODO.max-perf/09-grammar-cold-start.md +25 -0
  63. data/TODO.max-perf/10-parser-facade-hygiene.md +23 -0
  64. data/TODO.max-perf/11-ci-green-closeout.md +25 -0
  65. data/TODO.max-perf/12-require-boot-profile.md +25 -0
  66. data/TODO.max-perf/13-key-conversion-specs.md +26 -0
  67. data/TODO.max-perf/14-builder-call-handler-audit.md +28 -0
  68. data/TODO.parity-ee/00-overview.md +76 -0
  69. data/TODO.parity-ee/01-annex-g-rule-extraction.md +41 -0
  70. data/TODO.parity-ee/02-eeng-algorithm-inventory.md +8 -0
  71. data/TODO.parity-ee/03-eeng-oracle-harness.md +33 -0
  72. data/TODO.parity-ee/04-shtolo-concatenate.md +44 -0
  73. data/TODO.parity-ee/05-shtolo-longform-flatten.md +53 -0
  74. data/TODO.parity-ee/06-interface-scheduling-parity.md +47 -0
  75. data/TODO.parity-ee/07-semantic-checks-port.md +35 -0
  76. data/TODO.parity-ee/08-pretty-roundtrip-gate.md +27 -0
  77. data/TODO.parity-ee/09-smrl-index-and-listing.md +22 -0
  78. data/TODO.parity-ee/10-interface-dot-graph.md +21 -0
  79. data/TODO.parity-ee/11-import-eeng-tests.md +79 -0
  80. data/TODO.parity-ee/12-full-check-catalog.md +67 -0
  81. data/TODO.parity-ee/13-population-p21.md +54 -0
  82. data/TODO.parity-ee/14-shtolo-completion.md +44 -0
  83. data/TODO.parity-ee/15-part28-xml.md +51 -0
  84. data/TODO.parity-ee/16-compare-patch.md +48 -0
  85. data/TODO.parity-ee/17-official-tests.md +42 -0
  86. data/TODO.parity-ee/18-mim-mapping.md +47 -0
  87. data/TODO.parity-ee/19-architecture.md +97 -0
  88. data/TODO.parity-ee/parity-matrix.md +108 -0
  89. data/TODO.refpath-v2/00-overview.md +64 -0
  90. data/TODO.suma-improvements/00-overview.md +23 -0
  91. data/TODO.suma-improvements/01-prebuilt-platform-gems.md +33 -0
  92. data/TODO.suma-improvements/02-suma-e2e.md +39 -0
  93. data/TODO.suma-improvements/03-item-graph.md +22 -0
  94. data/TODO.suma-improvements/04-compiled-set-default.md +16 -0
  95. data/TODO.suma-improvements/05-validation-in-docs.md +17 -0
  96. data/TODO.suma-improvements/06-memory-remeasure.md +36 -0
  97. data/TODO.suma-improvements/07-part28-xml.md +15 -0
  98. data/TODO.suma-improvements/08-windows-gnu-toolchain.md +15 -0
  99. data/TODO.suma-improvements/09-checker-tranche3.md +13 -0
  100. data/TODO.suma-improvements/10-expressdoc.md +8 -0
  101. data/benchmark/srl_benchmark.rb +458 -0
  102. data/benchmark/srl_native_benchmark.rb +146 -0
  103. data/benchmark/srl_ruby_benchmark.rb +132 -0
  104. data/bin/console +11 -0
  105. data/bin/rspec +30 -0
  106. data/bin/setup +8 -0
  107. data/docs/Gemfile +12 -0
  108. data/docs/_config.yml +141 -0
  109. data/docs/_guides/changes/changes-format.adoc +778 -0
  110. data/docs/_guides/changes/importing-eengine.adoc +898 -0
  111. data/docs/_guides/changes/index.adoc +396 -0
  112. data/docs/_guides/changes/programmatic-usage.adoc +1038 -0
  113. data/docs/_guides/changes/validating-changes.adoc +681 -0
  114. data/docs/_guides/cli/benchmark-performance.adoc +834 -0
  115. data/docs/_guides/cli/coverage-analysis.adoc +921 -0
  116. data/docs/_guides/cli/format-schemas.adoc +547 -0
  117. data/docs/_guides/cli/index.adoc +8 -0
  118. data/docs/_guides/cli/managing-changes.adoc +927 -0
  119. data/docs/_guides/cli/validate-ascii.adoc +645 -0
  120. data/docs/_guides/cli/validate-schemas.adoc +534 -0
  121. data/docs/_guides/formatter/formatter-architecture.adoc +401 -0
  122. data/docs/_guides/index.adoc +165 -0
  123. data/docs/_guides/ler/creating-packages.adoc +664 -0
  124. data/docs/_guides/ler/index.adoc +305 -0
  125. data/docs/_guides/ler/loading-packages.adoc +707 -0
  126. data/docs/_guides/ler/package-formats.adoc +748 -0
  127. data/docs/_guides/ler/querying-packages.adoc +826 -0
  128. data/docs/_guides/ler/step-packages.adoc +385 -0
  129. data/docs/_guides/ler/validating-packages.adoc +750 -0
  130. data/docs/_guides/liquid/basic-templates.adoc +813 -0
  131. data/docs/_guides/liquid/documentation-generation.adoc +1042 -0
  132. data/docs/_guides/liquid/drops-reference.adoc +829 -0
  133. data/docs/_guides/liquid/filters-and-tags.adoc +912 -0
  134. data/docs/_guides/liquid/index.adoc +468 -0
  135. data/docs/_guides/manifests/creating-manifests.adoc +483 -0
  136. data/docs/_guides/manifests/index.adoc +307 -0
  137. data/docs/_guides/manifests/resolving-manifests.adoc +557 -0
  138. data/docs/_guides/manifests/validating-manifests.adoc +713 -0
  139. data/docs/_guides/ruby-api/formatting-schemas.adoc +605 -0
  140. data/docs/_guides/ruby-api/index.adoc +257 -0
  141. data/docs/_guides/ruby-api/parsing-files.adoc +421 -0
  142. data/docs/_guides/ruby-api/search-engine.adoc +609 -0
  143. data/docs/_guides/ruby-api/working-with-repository.adoc +577 -0
  144. data/docs/_pages/data-model.adoc +665 -0
  145. data/docs/_pages/express-language.adoc +506 -0
  146. data/docs/_pages/getting-started.adoc +414 -0
  147. data/docs/_pages/index.adoc +116 -0
  148. data/docs/_pages/introduction.adoc +256 -0
  149. data/docs/_pages/ler-packages.adoc +837 -0
  150. data/docs/_pages/parsers.adoc +709 -0
  151. data/docs/_pages/schema-manifests.adoc +431 -0
  152. data/docs/_references/index.adoc +228 -0
  153. data/docs/_tutorials/creating-ler-package.adoc +735 -0
  154. data/docs/_tutorials/documentation-coverage.adoc +795 -0
  155. data/docs/_tutorials/formatting-schemas.adoc +89 -0
  156. data/docs/_tutorials/index.adoc +231 -0
  157. data/docs/_tutorials/liquid-templates.adoc +806 -0
  158. data/docs/_tutorials/parsing-your-first-schema.adoc +522 -0
  159. data/docs/_tutorials/querying-schemas.adoc +751 -0
  160. data/docs/_tutorials/working-with-multiple-schemas.adoc +676 -0
  161. data/docs/index.adoc +242 -0
  162. data/docs/lychee.toml +90 -0
  163. data/examples/demo_ler_usage.sh +86 -0
  164. data/examples/ler/README.md +111 -0
  165. data/examples/ler/simple_example.ler +0 -0
  166. data/examples/ler/simple_schema.exp +33 -0
  167. data/examples/ler_build.rb +75 -0
  168. data/examples/ler_cli.rb +79 -0
  169. data/examples/ler_demo_complete.rb +276 -0
  170. data/examples/ler_query.rb +91 -0
  171. data/examples/ler_query_examples.rb +305 -0
  172. data/examples/ler_stats.rb +81 -0
  173. data/examples/phase3_demo.rb +159 -0
  174. data/examples/query_demo_simple.rb +131 -0
  175. data/exe/expressir +11 -0
  176. data/exe/expressir-format +14 -0
  177. data/exe/expressir-format-test +82 -0
  178. data/expressir.gemspec +61 -0
  179. data/lib/expressir/3.2/expressir_core.so +0 -0
  180. data/lib/expressir/3.3/expressir_core.so +0 -0
  181. data/lib/expressir/3.4/expressir_core.so +0 -0
  182. data/lib/expressir/4.0/expressir_core.so +0 -0
  183. data/lib/expressir/benchmark.rb +310 -0
  184. data/lib/expressir/changes/item_change.rb +20 -0
  185. data/lib/expressir/changes/mapping_change.rb +16 -0
  186. data/lib/expressir/changes/schema_change.rb +85 -0
  187. data/lib/expressir/changes/version_change.rb +26 -0
  188. data/lib/expressir/changes.rb +9 -0
  189. data/lib/expressir/cli.rb +148 -0
  190. data/lib/expressir/commands/base.rb +25 -0
  191. data/lib/expressir/commands/benchmark.rb +59 -0
  192. data/lib/expressir/commands/benchmark_cache.rb +80 -0
  193. data/lib/expressir/commands/changes.rb +34 -0
  194. data/lib/expressir/commands/changes_import_eengine.rb +146 -0
  195. data/lib/expressir/commands/changes_validate.rb +63 -0
  196. data/lib/expressir/commands/check.rb +56 -0
  197. data/lib/expressir/commands/clean.rb +20 -0
  198. data/lib/expressir/commands/coverage.rb +458 -0
  199. data/lib/expressir/commands/expand.rb +26 -0
  200. data/lib/expressir/commands/file_violations.rb +70 -0
  201. data/lib/expressir/commands/fix.rb +33 -0
  202. data/lib/expressir/commands/flatten.rb +29 -0
  203. data/lib/expressir/commands/format.rb +43 -0
  204. data/lib/expressir/commands/manifest.rb +420 -0
  205. data/lib/expressir/commands/mapping_validate.rb +68 -0
  206. data/lib/expressir/commands/non_ascii_character.rb +49 -0
  207. data/lib/expressir/commands/non_ascii_violation_collection.rb +301 -0
  208. data/lib/expressir/commands/package.rb +1222 -0
  209. data/lib/expressir/commands/parity_inputs.rb +160 -0
  210. data/lib/expressir/commands/validate.rb +106 -0
  211. data/lib/expressir/commands/validate_ascii.rb +94 -0
  212. data/lib/expressir/commands/validate_load.rb +91 -0
  213. data/lib/expressir/commands/version.rb +9 -0
  214. data/lib/expressir/commands/xsd.rb +23 -0
  215. data/lib/expressir/commands.rb +30 -0
  216. data/lib/expressir/config.rb +60 -0
  217. data/lib/expressir/coverage.rb +510 -0
  218. data/lib/expressir/eengine/arm_compare_report.rb +23 -0
  219. data/lib/expressir/eengine/changes_section.rb +16 -0
  220. data/lib/expressir/eengine/compare_report.rb +69 -0
  221. data/lib/expressir/eengine/mim_compare_report.rb +23 -0
  222. data/lib/expressir/eengine/modified_object.rb +21 -0
  223. data/lib/expressir/eengine.rb +9 -0
  224. data/lib/expressir/errors.rb +113 -0
  225. data/lib/expressir/express/adoc_hyperlink_formatter.rb +30 -0
  226. data/lib/expressir/express/adoc_source_formatter.rb +12 -0
  227. data/lib/expressir/express/ast_key_converter.rb +114 -0
  228. data/lib/expressir/express/builder.rb +277 -0
  229. data/lib/expressir/express/builder_context.rb +22 -0
  230. data/lib/expressir/express/builder_registry.rb +397 -0
  231. data/lib/expressir/express/builders/attribute_decl_builder.rb +32 -0
  232. data/lib/expressir/express/builders/built_in_builder.rb +75 -0
  233. data/lib/expressir/express/builders/constant_builder.rb +108 -0
  234. data/lib/expressir/express/builders/declaration_builder.rb +20 -0
  235. data/lib/expressir/express/builders/derive_clause_builder.rb +14 -0
  236. data/lib/expressir/express/builders/derived_attr_builder.rb +28 -0
  237. data/lib/expressir/express/builders/domain_rule_builder.rb +21 -0
  238. data/lib/expressir/express/builders/entity_decl_builder.rb +116 -0
  239. data/lib/expressir/express/builders/explicit_attr_builder.rb +49 -0
  240. data/lib/expressir/express/builders/expression_builder.rb +416 -0
  241. data/lib/expressir/express/builders/function_decl_builder.rb +86 -0
  242. data/lib/expressir/express/builders/helpers.rb +148 -0
  243. data/lib/expressir/express/builders/interface_builder.rb +151 -0
  244. data/lib/expressir/express/builders/inverse_attr_builder.rb +43 -0
  245. data/lib/expressir/express/builders/inverse_attr_type_builder.rb +30 -0
  246. data/lib/expressir/express/builders/inverse_clause_builder.rb +14 -0
  247. data/lib/expressir/express/builders/literal_builder.rb +93 -0
  248. data/lib/expressir/express/builders/procedure_decl_builder.rb +82 -0
  249. data/lib/expressir/express/builders/qualifier_builder.rb +102 -0
  250. data/lib/expressir/express/builders/reference_builder.rb +18 -0
  251. data/lib/expressir/express/builders/rule_decl_builder.rb +97 -0
  252. data/lib/expressir/express/builders/schema_body_decl_builder.rb +18 -0
  253. data/lib/expressir/express/builders/schema_decl_builder.rb +56 -0
  254. data/lib/expressir/express/builders/schema_version_builder.rb +34 -0
  255. data/lib/expressir/express/builders/simple_id_builder.rb +17 -0
  256. data/lib/expressir/express/builders/statement_builder.rb +243 -0
  257. data/lib/expressir/express/builders/subtype_constraint_builder.rb +166 -0
  258. data/lib/expressir/express/builders/syntax_builder.rb +30 -0
  259. data/lib/expressir/express/builders/type_builder.rb +238 -0
  260. data/lib/expressir/express/builders/type_decl_builder.rb +26 -0
  261. data/lib/expressir/express/builders/unique_clause_builder.rb +20 -0
  262. data/lib/expressir/express/builders/unique_rule_builder.rb +41 -0
  263. data/lib/expressir/express/builders/where_clause_builder.rb +20 -0
  264. data/lib/expressir/express/builders.rb +55 -0
  265. data/lib/expressir/express/cache.rb +76 -0
  266. data/lib/expressir/express/checker.rb +812 -0
  267. data/lib/expressir/express/concatenator.rb +79 -0
  268. data/lib/expressir/express/core.rb +95 -0
  269. data/lib/expressir/express/error.rb +124 -0
  270. data/lib/expressir/express/formatter.rb +149 -0
  271. data/lib/expressir/express/formatters/data_types_formatter.rb +362 -0
  272. data/lib/expressir/express/formatters/declarations_formatter.rb +753 -0
  273. data/lib/expressir/express/formatters/expressions_formatter.rb +180 -0
  274. data/lib/expressir/express/formatters/literals_formatter.rb +55 -0
  275. data/lib/expressir/express/formatters/references_formatter.rb +53 -0
  276. data/lib/expressir/express/formatters/remark_formatter.rb +270 -0
  277. data/lib/expressir/express/formatters/remark_item_formatter.rb +28 -0
  278. data/lib/expressir/express/formatters/statements_formatter.rb +272 -0
  279. data/lib/expressir/express/formatters/supertype_expressions_formatter.rb +54 -0
  280. data/lib/expressir/express/formatters.rb +22 -0
  281. data/lib/expressir/express/grammar/parser.rb +712 -0
  282. data/lib/expressir/express/grammar.rb +11 -0
  283. data/lib/expressir/express/hyperlink_formatter.rb +35 -0
  284. data/lib/expressir/express/interface_dot.rb +105 -0
  285. data/lib/expressir/express/lazy_repository.rb +211 -0
  286. data/lib/expressir/express/line_map.rb +48 -0
  287. data/lib/expressir/express/listing.rb +174 -0
  288. data/lib/expressir/express/model_traversal.rb +42 -0
  289. data/lib/expressir/express/model_visitor.rb +25 -0
  290. data/lib/expressir/express/node_position_index.rb +342 -0
  291. data/lib/expressir/express/parallel_files.rb +229 -0
  292. data/lib/expressir/express/parser.rb +523 -0
  293. data/lib/expressir/express/pretty_formatter.rb +586 -0
  294. data/lib/expressir/express/pretty_gate.rb +61 -0
  295. data/lib/expressir/express/refs_overlay.rb +47 -0
  296. data/lib/expressir/express/remark_attacher.rb +1098 -0
  297. data/lib/expressir/express/remark_overlay.rb +86 -0
  298. data/lib/expressir/express/remark_scanner.rb +245 -0
  299. data/lib/expressir/express/resolve_references_model_visitor.rb +29 -0
  300. data/lib/expressir/express/schema_block_scanner.rb +137 -0
  301. data/lib/expressir/express/schema_head_formatter.rb +22 -0
  302. data/lib/expressir/express/schema_plain_source_formatter.rb +11 -0
  303. data/lib/expressir/express/schema_source_formatter.rb +15 -0
  304. data/lib/expressir/express/scope_resolver.rb +223 -0
  305. data/lib/expressir/express/self_schema_reference.rb +126 -0
  306. data/lib/expressir/express/shtolo.rb +679 -0
  307. data/lib/expressir/express/smrl_xml.rb +125 -0
  308. data/lib/expressir/express/source_formatter.rb +15 -0
  309. data/lib/expressir/express/streaming_builder.rb +435 -0
  310. data/lib/expressir/express/xsd.rb +259 -0
  311. data/lib/expressir/express.rb +53 -0
  312. data/lib/expressir/liquid.rb +1 -0
  313. data/lib/expressir/manifest/resolver.rb +210 -0
  314. data/lib/expressir/manifest/validator.rb +192 -0
  315. data/lib/expressir/manifest.rb +6 -0
  316. data/lib/expressir/mapping/refpath.rb +857 -0
  317. data/lib/expressir/mapping.rb +253 -0
  318. data/lib/expressir/model/cache.rb +18 -0
  319. data/lib/expressir/model/concerns.rb +42 -0
  320. data/lib/expressir/model/data_types/aggregate.rb +26 -0
  321. data/lib/expressir/model/data_types/array.rb +25 -0
  322. data/lib/expressir/model/data_types/bag.rb +21 -0
  323. data/lib/expressir/model/data_types/binary.rb +19 -0
  324. data/lib/expressir/model/data_types/boolean.rb +15 -0
  325. data/lib/expressir/model/data_types/enumeration.rb +21 -0
  326. data/lib/expressir/model/data_types/enumeration_item.rb +24 -0
  327. data/lib/expressir/model/data_types/generic.rb +24 -0
  328. data/lib/expressir/model/data_types/generic_entity.rb +24 -0
  329. data/lib/expressir/model/data_types/integer.rb +15 -0
  330. data/lib/expressir/model/data_types/list.rb +23 -0
  331. data/lib/expressir/model/data_types/logical.rb +15 -0
  332. data/lib/expressir/model/data_types/number.rb +15 -0
  333. data/lib/expressir/model/data_types/real.rb +17 -0
  334. data/lib/expressir/model/data_types/select.rb +23 -0
  335. data/lib/expressir/model/data_types/set.rb +21 -0
  336. data/lib/expressir/model/data_types/string.rb +19 -0
  337. data/lib/expressir/model/data_types.rb +25 -0
  338. data/lib/expressir/model/declarations/attribute.rb +38 -0
  339. data/lib/expressir/model/declarations/constant.rb +28 -0
  340. data/lib/expressir/model/declarations/derived_attribute.rb +25 -0
  341. data/lib/expressir/model/declarations/entity.rb +62 -0
  342. data/lib/expressir/model/declarations/function.rb +59 -0
  343. data/lib/expressir/model/declarations/informal_proposition_rule.rb +25 -0
  344. data/lib/expressir/model/declarations/interface.rb +37 -0
  345. data/lib/expressir/model/declarations/interface_item.rb +21 -0
  346. data/lib/expressir/model/declarations/interfaced_item.rb +33 -0
  347. data/lib/expressir/model/declarations/inverse_attribute.rb +25 -0
  348. data/lib/expressir/model/declarations/parameter.rb +28 -0
  349. data/lib/expressir/model/declarations/procedure.rb +57 -0
  350. data/lib/expressir/model/declarations/remark_item.rb +21 -0
  351. data/lib/expressir/model/declarations/rule.rb +66 -0
  352. data/lib/expressir/model/declarations/schema.rb +215 -0
  353. data/lib/expressir/model/declarations/schema_version.rb +19 -0
  354. data/lib/expressir/model/declarations/schema_version_item.rb +19 -0
  355. data/lib/expressir/model/declarations/subtype_constraint.rb +32 -0
  356. data/lib/expressir/model/declarations/type.rb +45 -0
  357. data/lib/expressir/model/declarations/unique_rule.rb +26 -0
  358. data/lib/expressir/model/declarations/variable.rb +28 -0
  359. data/lib/expressir/model/declarations/where_rule.rb +26 -0
  360. data/lib/expressir/model/declarations.rb +31 -0
  361. data/lib/expressir/model/dependency_resolver.rb +268 -0
  362. data/lib/expressir/model/exp_file.rb +42 -0
  363. data/lib/expressir/model/expressions/aggregate_initializer.rb +18 -0
  364. data/lib/expressir/model/expressions/aggregate_initializer_item.rb +20 -0
  365. data/lib/expressir/model/expressions/binary_expression.rb +59 -0
  366. data/lib/expressir/model/expressions/entity_constructor.rb +20 -0
  367. data/lib/expressir/model/expressions/function_call.rb +20 -0
  368. data/lib/expressir/model/expressions/interval.rb +29 -0
  369. data/lib/expressir/model/expressions/query_expression.rb +31 -0
  370. data/lib/expressir/model/expressions/unary_expression.rb +25 -0
  371. data/lib/expressir/model/expressions.rb +18 -0
  372. data/lib/expressir/model/identifier.rb +26 -0
  373. data/lib/expressir/model/indexes/entity_index.rb +103 -0
  374. data/lib/expressir/model/indexes/item_graph.rb +185 -0
  375. data/lib/expressir/model/indexes/reference_index.rb +148 -0
  376. data/lib/expressir/model/indexes/type_index.rb +149 -0
  377. data/lib/expressir/model/indexes.rb +12 -0
  378. data/lib/expressir/model/interface_validator.rb +384 -0
  379. data/lib/expressir/model/literals/binary.rb +17 -0
  380. data/lib/expressir/model/literals/integer.rb +17 -0
  381. data/lib/expressir/model/literals/logical.rb +21 -0
  382. data/lib/expressir/model/literals/real.rb +17 -0
  383. data/lib/expressir/model/literals/string.rb +20 -0
  384. data/lib/expressir/model/literals.rb +13 -0
  385. data/lib/expressir/model/model_element.rb +377 -0
  386. data/lib/expressir/model/references/attribute_reference.rb +19 -0
  387. data/lib/expressir/model/references/group_reference.rb +19 -0
  388. data/lib/expressir/model/references/index_reference.rb +23 -0
  389. data/lib/expressir/model/references/simple_reference.rb +21 -0
  390. data/lib/expressir/model/references.rb +12 -0
  391. data/lib/expressir/model/remark_format.rb +17 -0
  392. data/lib/expressir/model/remark_info.rb +92 -0
  393. data/lib/expressir/model/remark_placement.rb +42 -0
  394. data/lib/expressir/model/repository.rb +483 -0
  395. data/lib/expressir/model/repository_validator.rb +293 -0
  396. data/lib/expressir/model/search_engine.rb +551 -0
  397. data/lib/expressir/model/statements/alias.rb +31 -0
  398. data/lib/expressir/model/statements/assignment.rb +23 -0
  399. data/lib/expressir/model/statements/case.rb +42 -0
  400. data/lib/expressir/model/statements/case_action.rb +20 -0
  401. data/lib/expressir/model/statements/compound.rb +21 -0
  402. data/lib/expressir/model/statements/escape.rb +18 -0
  403. data/lib/expressir/model/statements/if.rb +26 -0
  404. data/lib/expressir/model/statements/null.rb +18 -0
  405. data/lib/expressir/model/statements/procedure_call.rb +22 -0
  406. data/lib/expressir/model/statements/repeat.rb +40 -0
  407. data/lib/expressir/model/statements/return.rb +20 -0
  408. data/lib/expressir/model/statements/skip.rb +18 -0
  409. data/lib/expressir/model/statements.rb +20 -0
  410. data/lib/expressir/model/supertype_expressions/binary_supertype_expression.rb +25 -0
  411. data/lib/expressir/model/supertype_expressions/oneof_supertype_expression.rb +17 -0
  412. data/lib/expressir/model/supertype_expressions.rb +12 -0
  413. data/lib/expressir/model.rb +39 -0
  414. data/lib/expressir/package/builder.rb +231 -0
  415. data/lib/expressir/package/metadata.rb +79 -0
  416. data/lib/expressir/package/reader.rb +149 -0
  417. data/lib/expressir/package.rb +8 -0
  418. data/lib/expressir/schema_manifest.rb +159 -0
  419. data/lib/expressir/schema_manifest_entry.rb +15 -0
  420. data/lib/expressir/version.rb +8 -0
  421. data/lib/expressir.rb +94 -0
  422. data/lib/tasks/verify_remarks.rake +16 -0
  423. data/rakelib/native.rake +24 -0
  424. data/rakelib/oracle.rake +52 -0
  425. data/rakelib/verify_remarks.rake +16 -0
  426. metadata +692 -0
@@ -0,0 +1,679 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Expressir
4
+ module Express
5
+ # SHTOLO — short-to-long conversion per ISO 10303-11:2004 Annex G
6
+ # (expressir#32): flattens a multi-schema specification into a
7
+ # single ISO 10303-11:1994 longform schema.
8
+ #
9
+ # Two stages (annex-g-rules.md):
10
+ # G.1 multi-schema → intermediate `artifact` schema: interface
11
+ # closure copied as local declarations, renames resolved to
12
+ # original names, name clashes munged (G.NM.1), REFERENCE
13
+ # entities kept with the dependent-instantiability rule
14
+ # (G.1.6), select/rules/supertype expressions pruned (G.1.9).
15
+ # G.2 artifact → `longform`: extensible enums/selects resolved
16
+ # (G.2.3/G.2.4), subtype constraints eliminated (supertype
17
+ # expression → SUPERTYPE, total_over → rule, G.2.5), abstract
18
+ # entity → ABSTRACT SUPERTYPE, GENERIC_ENTITY → GENERIC,
19
+ # RENAMED → DERIVE (G.2.7), qualified strings rewritten.
20
+ #
21
+ # The output is a Model::Declarations::Schema named per the root
22
+ # schema; format it with the Formatter to obtain the longform file.
23
+ class Shtolo
24
+ DEPENDENT_RULE_NAME = "validate_dependently_instantiable_entity_data_types"
25
+ DEPENDENT_FN_NAME = "dependently_instantiated"
26
+
27
+ attr_reader :longform, :renames, :schema
28
+
29
+ # `root_schema` — the resolved root schema node.
30
+ # `repository` — must hold the full interface closure.
31
+ # `extenders` — :all (default, the WG12 requirement) folds every
32
+ # extensible SELECT/ENUMERATION extension found in the
33
+ # closure into its base type (Annex G.2.3/G.2.4);
34
+ # :none leaves extensible types exactly as declared —
35
+ # the shape eengine's default --flat emits.
36
+ # `prune` — true (default) runs the G.1.9 prune pass;
37
+ # false keeps the artifact's full declaration set.
38
+ # `stage` — :longform (default) runs the G.2 rewrites;
39
+ # :artifact stops after stage 1 — the annex's
40
+ # intermediate schema, the shape eengine's
41
+ # --concat_schema output corresponds to (copy
42
+ # pass, no prune, no 1994 rewrite).
43
+ def initialize(root_schema, repository, longform_name: nil,
44
+ extenders: :all, prune: true, stage: :longform)
45
+ @root = root_schema
46
+ @repository = repository
47
+ @longform_name = longform_name || @root.id
48
+ @extenders = extenders
49
+ @prune = prune
50
+ @stage = stage
51
+ @reference_entities = [] # G.1.6 entities
52
+ end
53
+
54
+ def flatten
55
+ @schema = build_longform
56
+ self
57
+ end
58
+
59
+ IdPlan = Struct.new(:global, :own_by_schema, keyword_init: true) do
60
+ def own(schema)
61
+ own_by_schema[schema] || {}
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ # ---- interface closure (same semantics as Concatenator) ----
68
+
69
+ def closure
70
+ @closure ||= begin
71
+ by_name = @repository.schemas.to_h { |s| [s.id.safe_downcase, s] }
72
+ visited = {}
73
+ queue = [@root]
74
+ until queue.empty?
75
+ schema = queue.shift
76
+ key = schema.id.safe_downcase
77
+ next if visited.key?(key)
78
+
79
+ visited[key] = schema
80
+ Array(schema.interfaces).each do |iface|
81
+ name = iface.schema.is_a?(String) ? iface.schema : iface.schema&.id
82
+ next unless name
83
+
84
+ target = by_name[name.safe_downcase]
85
+ queue << target if target && !visited.key?(name.safe_downcase)
86
+ end
87
+ end
88
+ visited
89
+ end
90
+ end
91
+
92
+ # ---- G.1 stage 1 ----
93
+
94
+ # Two-phase copy: plan every declaration's final id across the whole
95
+ # closure FIRST (G.NM.1 clashes are only known once every schema has
96
+ # been seen), then copy+rewrite each declaration against the complete
97
+ # map. Rewriting as we copy left stale references in declarations
98
+ # copied before a later clash was munged.
99
+ def build_artifact
100
+ schemas = [@root, *closure.values.reject { |s| s.equal?(@root) }]
101
+ plan = plan_ids(schemas)
102
+
103
+ declarations = []
104
+ schemas.each do |schema|
105
+ rename_map = renames_for(schema)
106
+ # Resolution order for a reference in this schema: its own local
107
+ # declarations (which may be munged), then interface aliases
108
+ # resolved through the referenced declaration's final id, then
109
+ # the global munge map for names the schema doesn't declare.
110
+ full = plan.global.dup
111
+ plan.own(schema).each { |k, final| full[k] = final }
112
+ rename_map.each do |alias_name, original|
113
+ resolved = plan.own(schema)[original.safe_downcase] ||
114
+ plan.global[original.safe_downcase] || original
115
+ full[alias_name.safe_downcase] = resolved
116
+ end
117
+
118
+ all_decls(schema).each do |decl|
119
+ copy = deep_copy(decl)
120
+ rewrite_references(copy, full)
121
+ if decl.respond_to?(:id) && decl.id &&
122
+ (final = plan.own(schema)[decl.id.safe_downcase])
123
+ copy.id = final
124
+ end
125
+ declarations << copy
126
+ end
127
+
128
+ # G.1.2: interfaces themselves dissolve; REFERENCE entities
129
+ # keep dependent-instantiability semantics (G.1.6).
130
+ schema.interfaces.each do |iface|
131
+ next unless iface.kind == Model::Declarations::Interface::REFERENCE
132
+
133
+ iface.items.each do |item|
134
+ original = original_name(item, schema)
135
+ next unless closure[original]&.entities&.find { |e| e.id == original }
136
+
137
+ @reference_entities << original.safe_downcase
138
+ end
139
+ end
140
+ end
141
+
142
+ declarations << build_dependent_rule if @reference_entities.any?
143
+
144
+ Model::Declarations::Schema.new(
145
+ id: @longform_name,
146
+ version: nil,
147
+ interfaces: [],
148
+ constants: declarations.grep(Model::Declarations::Constant).compact,
149
+ types: declarations.grep(Model::Declarations::Type).compact,
150
+ entities: declarations.grep(Model::Declarations::Entity).compact,
151
+ subtype_constraints: declarations.grep(Model::Declarations::SubtypeConstraint).compact,
152
+ functions: declarations.grep(Model::Declarations::Function).compact,
153
+ procedures: declarations.grep(Model::Declarations::Procedure).compact,
154
+ rules: declarations.grep(Model::Declarations::Rule).compact,
155
+ )
156
+ end
157
+
158
+ def all_decls(schema)
159
+ schema.constants + schema.types + schema.entities +
160
+ schema.subtype_constraints + schema.functions +
161
+ schema.rules + schema.procedures
162
+ end
163
+
164
+ # G.NM.1: the first schema in closure order to declare a name keeps
165
+ # it; every later declaration of the same name is prefixed with ITS
166
+ # OWN schema's id, and the global map redirects the bare name so
167
+ # declarations from third schemas resolve to the first occurrence.
168
+ def plan_ids(schemas)
169
+ seen_first = {} # downcase id => owning schema (first occurrence)
170
+ global = {} # downcase id => munged final
171
+ own_by_schema = {} # schema => {downcase id => final id}
172
+ schemas.each do |schema|
173
+ own = {}
174
+ all_decls(schema).each do |decl|
175
+ next unless decl.respond_to?(:id) && decl.id
176
+
177
+ key = decl.id.safe_downcase
178
+ if seen_first.key?(key)
179
+ final = "#{schema.id.safe_downcase}_dot_#{decl.id}"
180
+ own[key] = final
181
+ global[key] = final
182
+ else
183
+ seen_first[key] = schema
184
+ own[key] = decl.id
185
+ end
186
+ end
187
+ own_by_schema[schema] = own
188
+ end
189
+ IdPlan.new(global: global, own_by_schema: own_by_schema)
190
+ end
191
+
192
+ # Alias → original map applied when copying `schema`'s
193
+ # declarations: the aliases are declared by the schema's own
194
+ # interface items (`USE FROM s (orig AS alias)`, G.1.3).
195
+ def renames_for(schema)
196
+ map = {}
197
+ Array(schema.interfaces).each do |iface|
198
+ iface.items.each do |item|
199
+ original = item.ref.is_a?(String) ? item.ref : item.ref&.id
200
+ next unless original
201
+
202
+ map[item.id.safe_downcase] = original if item.id &&
203
+ item.id.safe_downcase != original.safe_downcase
204
+ end
205
+ end
206
+ map
207
+ end
208
+
209
+ def original_name(item, schema)
210
+ original = item.ref.is_a?(String) ? item.ref : item.ref&.id
211
+ return schema.id unless original
212
+
213
+ original
214
+ end
215
+
216
+ def deep_copy(obj)
217
+ sever = []
218
+ node = obj
219
+ while node.respond_to?(:parent) && node.parent
220
+ sever << node
221
+ node = node.parent
222
+ end
223
+ saved = sever.map(&:parent)
224
+ sever.each { |n| n.parent = nil }
225
+ Marshal.load(Marshal.dump(obj))
226
+ ensure
227
+ sever.each_with_index { |n, i| n.parent = saved[i] }
228
+ end
229
+
230
+ # Rewrite SimpleReference ids against a rename map in ONE tree walk
231
+ # (each declaration is walked once, whatever the map's size — walking
232
+ # once per rename made flattening quadratic in the closure).
233
+ # Map keys are downcased old names, values the final names.
234
+ def rewrite_references(node, map)
235
+ return unless node.is_a?(Model::ModelElement)
236
+
237
+ if node.is_a?(Model::References::SimpleReference) && node.id &&
238
+ (to = map[node.id.safe_downcase])
239
+ node.id = preserve_case(node.id, to)
240
+ end
241
+ node.class.attributes.each_key do |attr|
242
+ next if Model::ModelElement::SKIP_ATTRIBUTES.include?(attr) || attr == :parent
243
+
244
+ value = node.public_send(attr)
245
+ case value
246
+ when Array then value.each { |item| rewrite_references(item, map) }
247
+ when Model::ModelElement then rewrite_references(value, map)
248
+ end
249
+ end
250
+ end
251
+
252
+ def preserve_case(current, new)
253
+ current == current.upcase ? new.upcase : new
254
+ end
255
+
256
+ # G.1.6: parse-templates keep the annex rule/function verbatim.
257
+ def build_dependent_rule
258
+ list = @reference_entities.map(&:upcase).join(", ")
259
+ union = @reference_entities.join("+")
260
+ src = <<~EXP
261
+ SCHEMA __dependent__;
262
+ RULE #{DEPENDENT_RULE_NAME} FOR (#{list});
263
+ LOCAL
264
+ number_of_input_instances : INTEGER;
265
+ previous_in_chain : LIST OF GENERIC := [];
266
+ set_of_input_types : SET OF STRING := [];
267
+ all_instances : SET OF GENERIC := [];
268
+ END_LOCAL;
269
+ all_instances := #{union};
270
+ WHERE
271
+ wr1: dependently_instantiated(all_instances, set_of_input_types, previous_in_chain);
272
+ END_RULE;
273
+ END_SCHEMA;
274
+ EXP
275
+ parse_schema_snippet(src).schemas.first.rules.first
276
+ end
277
+
278
+ def parse_schema_snippet(src)
279
+ Expressir::Express::Parser.from_exp(src)
280
+ end
281
+
282
+ # ---- G.2 stage 2 ----
283
+
284
+ def build_longform
285
+ artifact = build_artifact
286
+ prune!(artifact) if @prune
287
+ return artifact if @stage == :artifact
288
+
289
+ if @extenders == :all
290
+ resolve_extensible_enumerations!(artifact)
291
+ resolve_extensible_selects!(artifact)
292
+ end
293
+ eliminate_subtype_constraints!(artifact)
294
+ convert_abstract_entities!(artifact)
295
+ convert_generic_entities!(artifact)
296
+ convert_renamed_attributes!(artifact)
297
+ rewrite_qualified_strings!(artifact)
298
+
299
+ artifact
300
+ end
301
+
302
+ # G.1.9 prune pass: the artifact keeps only what stays visible
303
+ # and reachable. Runs before the stage-2 rewrites so they never
304
+ # see declarations the longform would drop.
305
+ def prune!(schema)
306
+ visible_ids = visible_declaration_ids(schema)
307
+
308
+ # rules whose parameter entities are not all visible
309
+ schema.rules = schema.rules.reject do |rule|
310
+ Array(rule.applies_to).any? do |ref|
311
+ id = ref.is_a?(String) ? ref : ref.id
312
+ id && !visible_ids.key?(id.safe_downcase)
313
+ end
314
+ end
315
+
316
+ # select items pointing at declarations the artifact lacks
317
+ schema.types.each do |type|
318
+ next unless type.underlying_type.is_a?(Model::DataTypes::Select)
319
+
320
+ items = Array(type.underlying_type.items)
321
+ kept = items.select do |item|
322
+ item.id.nil? || visible_ids.key?(item.id.safe_downcase)
323
+ end
324
+ # An emptied select disappears from the representation
325
+ # (annex G.1.9 s1/s2/s3 example).
326
+ type.underlying_type.items = kept unless kept.empty? && items.empty?
327
+ if kept.empty? && !items.empty?
328
+ type.underlying_type = nil
329
+ end
330
+ end
331
+ schema.types = schema.types.reject { |t| t.underlying_type.nil? }
332
+
333
+ # functions/procedures nothing calls, to fixpoint (a helper only
334
+ # a dropped function called is itself unreachable)
335
+ loop do
336
+ called = called_ids(schema)
337
+ drop = schema.functions.any? { |f| !called[f.id.safe_downcase] } ||
338
+ schema.procedures.any? { |p| !called[p.id.safe_downcase] }
339
+ break unless drop
340
+
341
+ schema.functions = schema.functions.select { |f| called[f.id.safe_downcase] }
342
+ schema.procedures = schema.procedures.select { |p| called[p.id.safe_downcase] }
343
+ end
344
+
345
+ prune_supertype_expressions!(schema, visible_ids)
346
+ end
347
+
348
+ def visible_declaration_ids(schema)
349
+ all_decls(schema).each_with_object({}) do |decl, hash|
350
+ hash[decl.id.safe_downcase] = true if decl.respond_to?(:id) && decl.id
351
+ end
352
+ end
353
+
354
+ # Every identifier a call site or reference names, across the
355
+ # artifact's surviving declarations: FunctionCall for functions,
356
+ # ProcedureCall statements for procedures, and ANY SimpleReference
357
+ # naming a schema function/procedure — a zero-argument function
358
+ # used bare (`v < limit_value`) parses as a plain reference, not
359
+ # a FunctionCall, and dropping it would leave the longform with a
360
+ # dangling call. Over-retaining is safe: prune only decides what
361
+ # may be dropped.
362
+ def called_ids(schema)
363
+ invocable = (schema.functions.to_a + schema.procedures.to_a)
364
+ .map { |d| d.id.safe_downcase }
365
+ called = {}
366
+ each_node(schema) do |node|
367
+ id = nil
368
+ case node
369
+ when Expressir::Model::Expressions::FunctionCall
370
+ id = node.function.is_a?(String) ? node.function : node.function&.id
371
+ when Expressir::Model::Statements::ProcedureCall
372
+ id = node.procedure.is_a?(String) ? node.procedure : node.procedure&.id
373
+ when Model::References::SimpleReference
374
+ id = node.id
375
+ end
376
+ called[id.safe_downcase] = true if id && invocable.include?(id.safe_downcase)
377
+ end
378
+ called
379
+ end
380
+
381
+ # Annex C reductions over supertype expressions: references to
382
+ # invisible entities leave ONEOF; ONEOF(a) => a; AND/OR sides
383
+ # that become empty collapse; a vacuous expression deletes the
384
+ # constraint.
385
+ def prune_supertype_expressions!(schema, visible_ids)
386
+ keep = []
387
+ schema.subtype_constraints.each do |constraint|
388
+ expr = constraint.supertype_expression
389
+ if expr.nil?
390
+ # total-over-only constraints carry no expression; stage 2
391
+ # turns their TOTAL_OVER into a rule.
392
+ keep << constraint
393
+ next
394
+ end
395
+ reduced = reduce_supertype_expression(expr, visible_ids)
396
+ # Annex C: a vacuous expression deletes the constraint.
397
+ next if reduced.nil?
398
+
399
+ constraint.supertype_expression = reduced
400
+ keep << constraint
401
+ end
402
+ schema.subtype_constraints = keep
403
+ end
404
+
405
+ def reduce_supertype_expression(expr, visible_ids)
406
+ case expr
407
+ when Model::SupertypeExpressions::OneofSupertypeExpression
408
+ reduced = expr.operands.filter_map do |operand|
409
+ reduce_supertype_expression(operand, visible_ids)
410
+ end
411
+ return nil if reduced.empty?
412
+
413
+ reduced.one? ? reduced.first : reset_oneof(expr, reduced)
414
+ when Model::SupertypeExpressions::BinarySupertypeExpression
415
+ left = reduce_supertype_expression(expr.operand1, visible_ids)
416
+ right = reduce_supertype_expression(expr.operand2, visible_ids)
417
+ if left.nil?
418
+ return right
419
+ end
420
+ if right.nil?
421
+ return left
422
+ end
423
+
424
+ rebuild_binary(expr, left, right)
425
+ when Model::References::SimpleReference
426
+ id = expr.id
427
+ return nil if id && !visible_ids.key?(id.safe_downcase)
428
+
429
+ expr
430
+ else
431
+ expr
432
+ end
433
+ end
434
+
435
+ def reset_oneof(expr, refs)
436
+ copy = deep_copy(expr)
437
+ copy.operands = refs
438
+ copy
439
+ end
440
+
441
+ def rebuild_binary(expr, left, right)
442
+ copy = deep_copy(expr)
443
+ copy.operand1 = left
444
+ copy.operand2 = right
445
+ copy
446
+ end
447
+
448
+ def resolve_extensible_enumerations!(schema)
449
+ schema.types.select do |t|
450
+ t.underlying_type.is_a?(Model::DataTypes::Enumeration) && t.underlying_type.extensible
451
+ end.each do |base|
452
+ enum = base.underlying_type
453
+ extensions = schema.types.select do |t|
454
+ t.underlying_type.is_a?(Model::DataTypes::Enumeration) &&
455
+ !t.underlying_type.extensible &&
456
+ t.underlying_type.based_on&.id&.safe_downcase == base.id.safe_downcase
457
+ end
458
+ merged = enum.items.map(&:id) +
459
+ extensions.flat_map { |x| x.underlying_type.items.map(&:id) }
460
+ enum.items = merged.uniq.map { |id| Model::DataTypes::EnumerationItem.new(id: id) }
461
+ enum.extensible = false
462
+ enum.based_on = nil
463
+
464
+ extensions.each do |ext|
465
+ ext_items = ext.underlying_type.items.map(&:id)
466
+ exclusions = merged - ext_items
467
+ ext.underlying_type = Model::DataTypes::Enumeration.new(
468
+ items: enum.items,
469
+ )
470
+ ext.where_rules = exclusions.each_with_index.map do |item, i|
471
+ Model::Declarations::WhereRule.new(
472
+ id: "wr#{i + 1}",
473
+ expression: parse_expression("SELF <> #{item};"),
474
+ )
475
+ end
476
+ end
477
+ end
478
+ end
479
+
480
+ def resolve_extensible_selects!(schema)
481
+ schema.types.select do |t|
482
+ t.underlying_type.is_a?(Model::DataTypes::Select) && t.underlying_type.extensible
483
+ end.each do |base|
484
+ sel = base.underlying_type
485
+
486
+ # all-extenders for GENERIC_ENTITY selects (WG12 requirement,
487
+ # #32): the extenders are the entity types themselves — fold in
488
+ # every entity the artifact carries, so the longform select is
489
+ # complete against the closure. Flags stay as declared: the
490
+ # extensible/generic-entity markers are part of the shortform's
491
+ # semantics and are not expressir's to drop.
492
+ if sel.generic_entity
493
+ sel.items = schema.entities.map do |e|
494
+ Model::References::SimpleReference.new(id: e.id)
495
+ end
496
+ next
497
+ end
498
+
499
+ extensions = schema.types.select do |t|
500
+ t.underlying_type.is_a?(Model::DataTypes::Select) &&
501
+ !t.underlying_type.extensible &&
502
+ t.underlying_type.based_on&.id&.safe_downcase == base.id.safe_downcase
503
+ end
504
+ merged_items = sel.items +
505
+ extensions.flat_map { |x| x.underlying_type.items }
506
+ seen_ids = {}
507
+ uniq = merged_items.select do |item|
508
+ key = item.id.safe_downcase
509
+ next false if seen_ids.key?(key) || key.empty?
510
+
511
+ seen_ids[key] = true
512
+ end
513
+ sel.items = uniq
514
+ sel.extensible = false
515
+ sel.based_on = nil
516
+
517
+ extensions.each do |ext|
518
+ keep = ext.underlying_type.items.map { |i| i.id.upcase }
519
+ exclusions = uniq.reject { |i| keep.include?(i.id.upcase) }
520
+ base_ref = "#{@longform_name.upcase}.#{base.id.upcase}"
521
+ ext.underlying_type = Model::DataTypes::Select.new(
522
+ items: sel.items.map { |i| Model::References::SimpleReference.new(id: i.id) },
523
+ )
524
+ ext.where_rules = exclusions.each_with_index.map do |item, i|
525
+ Model::Declarations::WhereRule.new(
526
+ id: "wr#{i + 1}",
527
+ expression: parse_expression("NOT ('#{base_ref}.#{item.id.upcase}' IN TYPEOF(SELF));"),
528
+ )
529
+ end
530
+ end
531
+ end
532
+ end
533
+
534
+ def eliminate_subtype_constraints!(schema)
535
+ schema.subtype_constraints.each do |sc|
536
+ entity = schema.entities.find do |e|
537
+ e.id.safe_downcase == sc.applies_to&.id&.safe_downcase
538
+ end
539
+ next unless entity
540
+
541
+ if sc.supertype_expression
542
+ expr = sc.supertype_expression
543
+ entity.supertype_expression =
544
+ entity.supertype_expression ? combine_andor(entity.supertype_expression, expr) : expr
545
+ end
546
+ if entity.abstract
547
+ # G.2.6: abstract entity ⇒ ABSTRACT SUPERTYPE (formatter
548
+ # renders from abstract + supertype status).
549
+ end
550
+ next if Array(sc.total_over).empty?
551
+
552
+ rule_name = "total_over_#{sc.id}"
553
+ targets = Array(sc.total_over).map { |r| r.id.upcase }
554
+ supertype = sc.applies_to&.id
555
+ rule = parse_schema_snippet(<<~EXP).schemas.first.rules.first
556
+ SCHEMA __to__;
557
+ RULE #{rule_name} FOR (#{supertype.upcase});
558
+ WHERE
559
+ wr1: SIZEOF(QUERY(#{supertype.downcase}_i <* #{supertype} |
560
+ SIZEOF(['#{@longform_name.upcase}.#{targets.first}'] * TYPEOF(#{supertype.downcase}_i)) = 0)) = 0;
561
+ END_RULE;
562
+ END_SCHEMA;
563
+ EXP
564
+ rule.id = rule_name
565
+ schema.rules = Array(schema.rules) + [rule]
566
+ end
567
+ schema.subtype_constraints = []
568
+ end
569
+
570
+ def combine_andor(left, right)
571
+ Model::SupertypeExpressions::BinarySupertypeExpression.new(
572
+ operator: Model::SupertypeExpressions::BinarySupertypeExpression::ANDOR,
573
+ operand1: left, operand2: right
574
+ )
575
+ rescue StandardError
576
+ left
577
+ end
578
+
579
+ def convert_abstract_entities!(schema)
580
+ schema.entities.each do |entity|
581
+ next unless entity.abstract
582
+
583
+ entity.abstract = true # formatter renders ABSTRACT SUPERTYPE when supertype present
584
+ end
585
+ end
586
+
587
+ def convert_generic_entities!(schema)
588
+ each_node(schema) do |node|
589
+ replace_in_parent(node, Model::DataTypes::Generic.new) if node.is_a?(Model::DataTypes::GenericEntity)
590
+ end
591
+ end
592
+
593
+ def replace_in_parent(node, replacement)
594
+ parent = node.parent
595
+ return unless parent
596
+
597
+ parent.class.attributes.each_key do |attr|
598
+ next if Model::ModelElement::SKIP_ATTRIBUTES.include?(attr)
599
+
600
+ value = parent.public_send(attr)
601
+ case value
602
+ when Array
603
+ value.each_with_index do |item, index|
604
+ parent.public_send(attr)[index] = replacement if item.equal?(node)
605
+ end
606
+ else
607
+ parent.public_send(:"#{attr}=", replacement) if value.equal?(node) && parent.respond_to?(:"#{attr}=")
608
+ end
609
+ end
610
+ end
611
+
612
+ def convert_renamed_attributes!(schema)
613
+ schema.entities.each do |entity|
614
+ entity.attributes.each_with_index do |attr, i|
615
+ next unless attr.supertype_attribute
616
+
617
+ old_name, supertype = supertype_target(attr.supertype_attribute)
618
+ entity.attributes[i] = Model::Declarations::DerivedAttribute.new(
619
+ id: attr.id || old_name,
620
+ type: attr.type,
621
+ expression: parse_expression("SELF\\#{supertype}.#{old_name}"),
622
+ )
623
+ end
624
+ end
625
+ end
626
+
627
+ # `SELF\ENTITY.attr` parses as AttributeReference(ref: GroupReference
628
+ # (SELF, entity), attribute: attr); a bare qualified attribute has
629
+ # only the attribute name.
630
+ def supertype_target(ref)
631
+ return [ref.id, nil] unless ref.is_a?(Model::References::AttributeReference)
632
+
633
+ group = ref.ref
634
+ [ref.attribute&.id,
635
+ group.is_a?(Model::References::GroupReference) ? group.entity&.id : nil]
636
+ end
637
+
638
+ # G.NM.2: string literals carrying schema-qualified names (e.g.
639
+ # TYPEOF arguments 'SCHEMA.TYPE') move to the longform name.
640
+ # Structurally these appear as DataTypes::String; path references
641
+ # in expressions are already renamed by the copy pass.
642
+ def rewrite_qualified_strings!(schema)
643
+ prefixes = closure.keys.map(&:upcase)
644
+ each_node(schema) do |node|
645
+ next unless node.is_a?(Model::Literals::String) && node.value
646
+
647
+ node.value = node.value.sub(/\A(#{prefixes.join('|')})\./i,
648
+ "#{@longform_name.upcase}.")
649
+ end
650
+ end
651
+
652
+ # Attribute-driven structural traversal over the whole subtree.
653
+ def each_node(root, &)
654
+ stack = [root]
655
+ until stack.empty?
656
+ node = stack.pop
657
+ yield node
658
+ next unless node.is_a?(Model::ModelElement)
659
+
660
+ node.class.attributes.each_key do |attr|
661
+ next if Model::ModelElement::SKIP_ATTRIBUTES.include?(attr)
662
+
663
+ value = node.public_send(attr)
664
+ case value
665
+ when Array then value.each { |item| stack << item if item.is_a?(Model::ModelElement) }
666
+ when Model::ModelElement then stack << value
667
+ end
668
+ end
669
+ end
670
+ end
671
+
672
+ def parse_expression(src)
673
+ snippet = "SCHEMA __x__; ENTITY __e__; WHERE w1 : #{src.chomp(';')}; END_ENTITY; END_SCHEMA;"
674
+ parsed = parse_schema_snippet(snippet)
675
+ parsed.schemas.first.entities.first.where_rules.first.expression
676
+ end
677
+ end
678
+ end
679
+ end