expressir 2.4.29-arm-linux-musl

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,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Expressir
4
+ module Express
5
+ # EXPRESS grammar namespace. Houses the Parsanol grammar definition
6
+ # separate from the I/O orchestration on the outer Parser facade.
7
+ module Grammar
8
+ autoload :Parser, "#{__dir__}/grammar/parser"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,35 @@
1
+ module Expressir
2
+ module Express
3
+ # Formatter module - format references as hyperlinks
4
+ # @example Include into Formatter subclass
5
+ # formatter = Class.new(Expressir::Express::Formatter) do
6
+ # include Expressir::Express::HyperlinkFormatter
7
+ # end
8
+ module HyperlinkFormatter
9
+ # @!visibility private
10
+ def self.included(mod)
11
+ unless mod.superclass <= Expressir::Express::Formatter
12
+ raise Error::FormatterMethodMissingError.new("HyperlinkFormatter",
13
+ "format_references_simple_reference")
14
+ end
15
+ end
16
+
17
+ def format_references_simple_reference(node)
18
+ return node.id unless node.base_path
19
+
20
+ # find closest node with path
21
+ current_node = node
22
+ while !current_node.path
23
+ current_node = current_node.parent
24
+ end
25
+
26
+ # skip if this reference and target node are in the same node with path
27
+ node_base_path_parts = node.base_path.split(".")
28
+ current_node_path_parts = current_node.path.split(".")
29
+ return node.id if node_base_path_parts[0..1] == current_node_path_parts[0..1]
30
+
31
+ "{{{<<express:#{node.base_path},#{node.id}>>}}}"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Expressir
4
+ module Express
5
+ # Interface dependency GraphViz emitter — port of eeng
6
+ # kernel/dot-graph.lisp `:interface` graph (parity-ee stage 10).
7
+ #
8
+ # Nodes are schema names (lowercase); edges are USE FROM (default
9
+ # blue) and REFERENCE FROM (default green). An edge with an item
10
+ # list uses arrowhead=curve; a bare interface uses arrowhead=normal.
11
+ class InterfaceDot
12
+ def initialize(root_schema, repository,
13
+ iface: :both, uf_color: :blue, rf_color: :green,
14
+ depth: nil, prune: [])
15
+ @root = root_schema
16
+ @repository = repository
17
+ @iface = iface
18
+ @uf_color = uf_color
19
+ @rf_color = rf_color
20
+ @depth = depth
21
+ @prune = Array(prune).map { |n| n.to_s.downcase }
22
+ @by_name = repository.schemas.compact.to_h { |s| [s.id.safe_downcase, s] }
23
+ end
24
+
25
+ def write(io = nil)
26
+ owned = io.nil?
27
+ io ||= +""
28
+ schemas, edges = collect
29
+ io << "// -*- Mode: Dot -*-\n\n"
30
+ io << "// Dot File Written by Expressir\n"
31
+ io << "// #{Expressir::VERSION}\n"
32
+ io << "\ndigraph interfaces {\n"
33
+ io << " node [shape=none];\n"
34
+ if %i[both use].include?(@iface)
35
+ io << " edge [color=#{@uf_color}];\n"
36
+ edges.select { |e| e[:kind] == :use }.each do |e|
37
+ head = e[:items] ? "curve" : "normal"
38
+ io << " #{e[:from]} -> #{e[:to]} [arrowhead=#{head}];\n"
39
+ end
40
+ end
41
+ if %i[both ref].include?(@iface)
42
+ io << " edge [color=#{@rf_color}];\n"
43
+ edges.select { |e| e[:kind] == :ref }.each do |e|
44
+ head = e[:items] ? "curve" : "normal"
45
+ io << " #{e[:from]} -> #{e[:to]} [arrowhead=#{head}];\n"
46
+ end
47
+ end
48
+ # Ensure isolated schemas still appear as nodes.
49
+ named = edges.flat_map { |e| [e[:from], e[:to]] }.uniq
50
+ (schemas.map { |s| s.id.downcase } - named).each do |n|
51
+ io << " #{n};\n"
52
+ end
53
+ io << "}\n"
54
+ owned ? io : nil
55
+ end
56
+
57
+ private
58
+
59
+ def collect
60
+ visited = {}
61
+ edges = []
62
+ queue = [[@root, 0]]
63
+ until queue.empty?
64
+ schema, level = queue.shift
65
+ key = schema.id.safe_downcase
66
+ next if visited.key?(key)
67
+ next if @prune.include?(key)
68
+
69
+ visited[key] = schema
70
+
71
+ Array(schema.interfaces).each do |iface|
72
+ target_name = iface_schema_name(iface)
73
+ next unless target_name
74
+
75
+ tkey = target_name.safe_downcase
76
+ next if @prune.include?(tkey)
77
+ next if tkey == key
78
+
79
+ kind = iface.kind == Model::Declarations::Interface::REFERENCE ? :ref : :use
80
+ next if @iface == :use && kind != :use
81
+ next if @iface == :ref && kind != :ref
82
+
83
+ edges << {
84
+ kind: kind,
85
+ items: Array(iface.items).any?,
86
+ from: key,
87
+ to: tkey,
88
+ }
89
+
90
+ target = @by_name[tkey]
91
+ next unless target
92
+ next if @depth && level + 1 >= @depth
93
+
94
+ queue << [target, level + 1]
95
+ end
96
+ end
97
+ [visited.values, edges.uniq]
98
+ end
99
+
100
+ def iface_schema_name(iface)
101
+ iface.schema.is_a?(String) ? iface.schema : iface.schema&.id
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,211 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "liquid"
4
+
5
+ module Expressir
6
+ module Express
7
+ # Lazy read path over a compiled-set artifact (M2 slice 2,
8
+ # TODO.parity-ee/19): schemas hydrate individually, on first touch,
9
+ # instead of the whole repository at once. Metanorma schema-doc
10
+ # rendering touches one schema per page — the lazy repository makes
11
+ # that pay: one hydration per page, not one per schema in the set.
12
+ #
13
+ # Duck-types the read surface of Model::Repository used by
14
+ # rendering (schemas, files, each, size, children). Anything beyond
15
+ # the read surface should wait for eager hydration via
16
+ # #to_eager (returns a real Model::Repository).
17
+ class LazyRepository
18
+ attr_reader :set_path
19
+
20
+ # @param set_path [String] compiled-set artifact path
21
+ # @param read_paths [Hash{String => String}] wire path => source path
22
+ def initialize(set_path, read_paths = {})
23
+ @set_path = set_path
24
+ @set = Core.lazy_set(set_path)
25
+ @read_paths = read_paths
26
+ @wire_paths = @set.wire_paths
27
+ @mutex = Mutex.new
28
+ @file_cache = {}
29
+ @hydration_count = 0
30
+ end
31
+
32
+ # Wire paths in artifact order — no hydration.
33
+ # @return [Array<String>]
34
+ def wire_paths
35
+ @wire_paths.dup
36
+ end
37
+
38
+ # Files in artifact order, each wrapped so it hydrates on first
39
+ # use. The file is the hydration grain: an artifact stores wire
40
+ # JSON per source file.
41
+ # @return [Array<LazyFile>]
42
+ def files
43
+ @wire_paths.map { |wire_path| file_by_wire_path(wire_path) }
44
+ end
45
+
46
+ # Hydrated (or hydrating) file for one wire path.
47
+ def file_by_wire_path(wire_path)
48
+ @mutex.synchronize do
49
+ @file_cache[wire_path] ||= LazyFile.new(wire_path) do
50
+ hydrate(wire_path)
51
+ end
52
+ end
53
+ end
54
+
55
+ # Schemas across all files. EAGER by definition: it hydrates
56
+ # every file. Lazy callers iterate #files, or render through
57
+ # #to_liquid, which keeps per-file hydration lazy.
58
+ # @return [Array<Declarations::Schema>]
59
+ def schemas
60
+ files.map(&:__target__).flat_map(&:schemas).compact
61
+ end
62
+
63
+ # Liquid binding for metanorma (M2): returns a Drop whose
64
+ # `schemas` is a lazy per-file list — each entry hydrates only
65
+ # its own file when the template touches it. Schema count per
66
+ # file is unknown until hydration, so the Drop presents one
67
+ # entry per FILE; single-schema files (the corpus norm) render
68
+ # identically to the eager path.
69
+ def to_liquid
70
+ LazyRepositoryDrop.new(self)
71
+ end
72
+
73
+ # How many files have actually been hydrated (observability for
74
+ # the laziness contract).
75
+ def hydration_count
76
+ @hydration_count
77
+ end
78
+
79
+ # Hydrate everything and return a real Model::Repository — the
80
+ # escape hatch for callers needing the full read surface.
81
+ def to_eager
82
+ repo = Model::Repository.new
83
+ repo.files = files.map(&:__target__)
84
+ repo
85
+ end
86
+
87
+ def each(&)
88
+ files.each(&)
89
+ end
90
+
91
+ def size
92
+ @wire_paths.size
93
+ end
94
+
95
+ def children
96
+ schemas
97
+ end
98
+
99
+ # The read path on disk for a wire path (may be nil when the
100
+ # caller did not supply source paths).
101
+ def read_path_for(wire_path)
102
+ @read_paths[wire_path]
103
+ end
104
+
105
+ def matches_sources?
106
+ @set.matches_sources(@read_paths.dup) == true
107
+ end
108
+
109
+ private
110
+
111
+ def hydrate(wire_path)
112
+ @mutex.synchronize do
113
+ _wire, model = @set.hydrate_one(wire_path)
114
+ @hydration_count += 1
115
+ model
116
+ end
117
+ end
118
+ end
119
+
120
+ # Liquid::Drop over a LazyRepository: `schemas` enumerates lazy
121
+ # per-file entries; touching an entry hydrates that file and
122
+ # presents its schemas (single-schema files present the schema
123
+ # itself, matching the eager Drop's element contract).
124
+ class LazyRepositoryDrop < ::Liquid::Drop
125
+ def initialize(repo)
126
+ @repo = repo
127
+ super()
128
+ end
129
+
130
+ def schemas
131
+ @repo.files.map do |file|
132
+ LazyFileDrop.new(file)
133
+ end
134
+ end
135
+
136
+ def size
137
+ @repo.size
138
+ end
139
+ end
140
+
141
+ # Per-file lazy drop: hydrates on first access, then presents the
142
+ # file's single schema directly (or the schema list for
143
+ # multi-schema files).
144
+ class LazyFileDrop < ::Liquid::Drop
145
+ def initialize(file)
146
+ @file = file
147
+ super()
148
+ end
149
+
150
+ def __file__
151
+ @file.__target__
152
+ end
153
+
154
+ def method_missing(name, *, &)
155
+ schemas = __file__.schemas
156
+ if schemas.size == 1
157
+ schemas.first.public_send(name, *, &)
158
+ else
159
+ __file__.public_send(name, *, &)
160
+ end
161
+ end
162
+
163
+ def respond_to_missing?(name, include_private = false)
164
+ __file__.respond_to?(name, include_private) ||
165
+ __file__.schemas.first.respond_to?(name, include_private)
166
+ end
167
+ end
168
+
169
+ # Stands in for a Model::ExpFile until first method access, then
170
+ # hydrates through the block and forwards everything.
171
+ class LazyFile
172
+ def initialize(wire_path, &hydrator)
173
+ @wire_path = wire_path
174
+ @hydrator = hydrator
175
+ @mutex = Mutex.new
176
+ @target = nil
177
+ end
178
+
179
+ attr_reader :wire_path
180
+
181
+ # The real Schema, hydrating on first call.
182
+ def __target__
183
+ @mutex.synchronize do
184
+ @__target__ ||= @hydrator.call
185
+ end
186
+ end
187
+
188
+ def method_missing(name, *, &)
189
+ __target__.public_send(name, *, &)
190
+ end
191
+
192
+ def respond_to_missing?(name, include_private = false)
193
+ __target__.respond_to?(name, include_private)
194
+ end
195
+
196
+ # Identity through the wrapper: rendering compares and groups by
197
+ # class/is_a?, which the real file answers.
198
+ def is_a?(klass)
199
+ super || __target__.is_a?(klass)
200
+ end
201
+
202
+ def instance_of?(klass)
203
+ __target__.instance_of?(klass)
204
+ end
205
+
206
+ def class
207
+ __target__.class
208
+ end
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Expressir
4
+ module Express
5
+ # Maps byte positions in a source string to 1-based line numbers.
6
+ #
7
+ # Single source of truth for byte→line lookup across the remark pipeline
8
+ # (RemarkScanner and RemarkAttacher both rely on it). Builds an offset
9
+ # table once and answers queries in O(log n) via binary search.
10
+ class LineMap
11
+ # Newline byte (ASCII 0x0A).
12
+ NEWLINE = "\n"
13
+
14
+ # @param source_bytes [String] BINARY / ASCII-8BIT encoded source.
15
+ def initialize(source_bytes)
16
+ @offsets = build_offsets(source_bytes)
17
+ end
18
+
19
+ # Returns the 1-based line number that contains the given byte position.
20
+ # Returns 1 for position 0 (or any position before the first newline).
21
+ # Returns the last line number for positions past the final newline.
22
+ #
23
+ # @param byte_pos [Integer, nil]
24
+ # @return [Integer] 1-based line number; nil input yields 1.
25
+ def line_number(byte_pos)
26
+ return 1 if byte_pos.nil? || byte_pos <= 0
27
+
28
+ idx = @offsets.bsearch_index { |offset| offset > byte_pos }
29
+ idx || @offsets.size
30
+ end
31
+
32
+ private
33
+
34
+ # Builds the sorted array of byte positions where each line begins.
35
+ # offsets[0] = 0 (line 1 begins at byte 0).
36
+ # offsets[i] = (byte position of the i-th newline) + 1 (line i+1 begins).
37
+ def build_offsets(source_bytes)
38
+ offsets = [0]
39
+ i = 0
40
+ while (i = source_bytes.index(NEWLINE, i))
41
+ offsets << (i + 1)
42
+ i += 1
43
+ end
44
+ offsets
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,174 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+
5
+ module Expressir
6
+ module Express
7
+ # Declaration listing and SMRL index writers — ports of eeng
8
+ # plugins/p11/wo-list.lisp and wo-smrl-xml.lisp (parity-ee stage 09).
9
+ #
10
+ # Two encodings share the same schema walk and declaration ordering
11
+ # (TYPE, ENTITY, SUBTYPE_CONSTRAINT, FUNCTION, RULE, PROCEDURE —
12
+ # each sorted by name):
13
+ # :list — human-readable SCHEMA.name; inventory
14
+ # :smrl_xml — <concatenated_express_file_content_list> index
15
+ class Listing
16
+ DECL_ORDER = %i[types entities subtype_constraints functions rules procedures].freeze
17
+ DECL_LABEL = {
18
+ types: "TYPE",
19
+ entities: "ENTITY",
20
+ subtype_constraints: "SUBTYPE_CONSTRAINT",
21
+ functions: "FUNCTION",
22
+ rules: "RULE",
23
+ procedures: "PROCEDURE",
24
+ }.freeze
25
+ XML_TAG = {
26
+ types: "type",
27
+ entities: "entity",
28
+ subtype_constraints: "subtype_constraint",
29
+ functions: "function",
30
+ rules: "rule",
31
+ procedures: "procedure",
32
+ }.freeze
33
+
34
+ def self.list(schemas, io = nil)
35
+ new(Array(schemas)).write(:list, io)
36
+ end
37
+
38
+ def self.smrl_xml(schemas, io = nil, source: nil)
39
+ new(Array(schemas)).write(:smrl_xml, io, source: source)
40
+ end
41
+
42
+ def initialize(schemas)
43
+ @schemas = schemas.compact.sort_by { |s| s.id.to_s.downcase }
44
+ end
45
+
46
+ def write(encoding, io = nil, source: nil)
47
+ owned = io.nil?
48
+ io ||= +""
49
+ case encoding
50
+ when :list then write_list(io)
51
+ when :smrl_xml then write_smrl_xml(io, source: source)
52
+ else
53
+ raise ArgumentError, "unknown listing encoding #{encoding.inspect}"
54
+ end
55
+ owned ? io : nil
56
+ end
57
+
58
+ private
59
+
60
+ def write_list(io)
61
+ @schemas.each_with_index do |schema, i|
62
+ io << "\n" if i.positive?
63
+ write_schema_list(schema, io)
64
+ end
65
+ end
66
+
67
+ def write_schema_list(schema, io)
68
+ version = schema.version ? " #{schema.version}" : ""
69
+ io << "SCHEMA #{schema.id.downcase}#{version};\n\n"
70
+ counts = decl_counts(schema)
71
+ DECL_ORDER.each do |key|
72
+ io << format("(* %-20s %4d *)\n", DECL_LABEL[key], counts[key])
73
+ end
74
+ ifaces = Array(schema.interfaces)
75
+ if ifaces.any?
76
+ io << "\n"
77
+ ifaces.each do |iface|
78
+ kind = iface.kind == Model::Declarations::Interface::REFERENCE ? "REFERENCE FROM" : "USE FROM"
79
+ target = iface_name(iface)
80
+ suffix = Array(iface.items).any? ? "(...)" : ""
81
+ io << " #{kind} #{target}#{suffix};\n"
82
+ end
83
+ end
84
+ constants = Array(schema.constants).sort_by { |c| c.id.to_s.downcase }
85
+ if constants.any?
86
+ io << "\n"
87
+ constants.each { |c| io << " CONSTANT #{c.id.downcase};\n" }
88
+ end
89
+ decls = ordered_decls(schema)
90
+ if decls.any?
91
+ io << "\n"
92
+ decls.each do |key, name|
93
+ io << " #{DECL_LABEL[key]} #{schema.id}.#{name.downcase};\n"
94
+ end
95
+ end
96
+ end
97
+
98
+ def write_smrl_xml(io, source: nil)
99
+ io << "<!-- Written by Expressir -->\n"
100
+ io << "<!-- #{Expressir::VERSION} -->\n"
101
+ io << "<!-- File: #{source} -->\n" if source
102
+ io << "<concatenated_express_file_content_list>\n\n"
103
+ names = @schemas.map { |s| schema_name_string(s.id) }
104
+ io << "<!-- #{@schemas.size} Schema#{'ta' unless @schemas.size == 1}:\n"
105
+ io << " #{names.join(', ')}\n"
106
+ io << "-->\n"
107
+ @schemas.each do |schema|
108
+ io << "\n\n"
109
+ write_schema_xml(schema, io)
110
+ end
111
+ io << "\n</concatenated_express_file_content_list>\n"
112
+ end
113
+
114
+ def write_schema_xml(schema, io)
115
+ io << "<schema>#{schema_name_string(schema.id)}</schema>\n"
116
+ if schema.version
117
+ io << " <schema_version>#{schema.version}</schema_version>\n"
118
+ end
119
+ counts = decl_counts(schema)
120
+ DECL_ORDER.each do |key|
121
+ io << format(" <!-- %-20s %4d -->\n", DECL_LABEL[key], counts[key])
122
+ end
123
+ Array(schema.interfaces).each do |iface|
124
+ tag = iface.kind == Model::Declarations::Interface::REFERENCE ? "reference-from" : "use-from"
125
+ target = iface_name(iface)
126
+ suffix = Array(iface.items).any? ? "(...)" : ""
127
+ io << " <#{tag}>#{target}#{suffix}</#{tag}>\n"
128
+ end
129
+ Array(schema.constants).sort_by { |c| c.id.to_s.downcase }.each do |c|
130
+ io << " <constant>#{c.id.downcase}</constant>\n"
131
+ end
132
+ ordered_decls(schema).each do |key, name|
133
+ tag = XML_TAG[key] || key.to_s
134
+ cased = if key == :entities && arm_mode?(schema)
135
+ name.split("_").map(&:capitalize).join("_")
136
+ else
137
+ name.downcase
138
+ end
139
+ io << " <#{tag}>#{schema.id}.#{cased}</#{tag}>\n"
140
+ end
141
+ end
142
+
143
+ def decl_counts(schema)
144
+ DECL_ORDER.to_h { |k| [k, Array(schema.public_send(k)).size] }
145
+ end
146
+
147
+ def ordered_decls(schema)
148
+ DECL_ORDER.flat_map do |key|
149
+ Array(schema.public_send(key))
150
+ .sort_by { |d| d.id.to_s.downcase }
151
+ .map { |d| [key, d.id] }
152
+ end
153
+ end
154
+
155
+ def iface_name(iface)
156
+ name = iface.schema.is_a?(String) ? iface.schema : iface.schema&.id
157
+ schema_name_string(name)
158
+ end
159
+
160
+ # eeng schema-name-string: arm/mim/arm_lf/mim_lf tails stay lowercase;
161
+ # everything else downcased.
162
+ def schema_name_string(name)
163
+ return "" unless name
164
+
165
+ name.to_s.downcase
166
+ end
167
+
168
+ def arm_mode?(schema)
169
+ id = schema.id.to_s.downcase
170
+ id.end_with?("arm", "arm_lf")
171
+ end
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Expressir
4
+ module Express
5
+ # Structural traversal over model trees, mirroring {ModelVisitor}:
6
+ # every typed attribute, statements included. Nodes are keyed by
7
+ # attribute path plus array index — stable across a compiled-set
8
+ # round trip because the wire is byte-identical — which is what the
9
+ # remark and reference overlays key on ({Model::ModelElement#path}
10
+ # is empty for id-less nodes).
11
+ module ModelTraversal
12
+ module_function
13
+
14
+ def each_node(node, key, &block)
15
+ yield node, key
16
+ return unless node.is_a?(Model::ModelElement)
17
+
18
+ node.class.attributes.each_key do |attr|
19
+ next if Model::ModelElement::SKIP_ATTRIBUTES.include?(attr) || attr == :parent
20
+
21
+ value = node.public_send(attr)
22
+ case value
23
+ when Array
24
+ value.each_with_index do |item, index|
25
+ next unless item.is_a?(Model::ModelElement)
26
+
27
+ each_node(item, "#{key}/#{attr}[#{index}]", &block)
28
+ end
29
+ when Model::ModelElement
30
+ each_node(value, "#{key}/#{attr}", &block)
31
+ end
32
+ end
33
+ end
34
+
35
+ def each_model(models, &block)
36
+ models.each_with_index do |model, index|
37
+ each_node(model, "model[#{index}]", &block)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,25 @@
1
+ module Expressir
2
+ module Express
3
+ # @abstract
4
+ class ModelVisitor
5
+ def visit(node)
6
+ node.class.attributes.each_key do |symbol|
7
+ next if ::Expressir::Model::ModelElement::SKIP_ATTRIBUTES.include?(symbol)
8
+
9
+ value = node.public_send(symbol)
10
+
11
+ case value
12
+ when Array
13
+ value.each do |val|
14
+ if val.is_a? Model::ModelElement
15
+ visit(val)
16
+ end
17
+ end
18
+ when Model::ModelElement
19
+ visit(value)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end