expressir 2.4.29-aarch64-mingw-ucrt

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 (424) 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.4/expressir_core.so +0 -0
  180. data/lib/expressir/4.0/expressir_core.so +0 -0
  181. data/lib/expressir/benchmark.rb +310 -0
  182. data/lib/expressir/changes/item_change.rb +20 -0
  183. data/lib/expressir/changes/mapping_change.rb +16 -0
  184. data/lib/expressir/changes/schema_change.rb +85 -0
  185. data/lib/expressir/changes/version_change.rb +26 -0
  186. data/lib/expressir/changes.rb +9 -0
  187. data/lib/expressir/cli.rb +148 -0
  188. data/lib/expressir/commands/base.rb +25 -0
  189. data/lib/expressir/commands/benchmark.rb +59 -0
  190. data/lib/expressir/commands/benchmark_cache.rb +80 -0
  191. data/lib/expressir/commands/changes.rb +34 -0
  192. data/lib/expressir/commands/changes_import_eengine.rb +146 -0
  193. data/lib/expressir/commands/changes_validate.rb +63 -0
  194. data/lib/expressir/commands/check.rb +56 -0
  195. data/lib/expressir/commands/clean.rb +20 -0
  196. data/lib/expressir/commands/coverage.rb +458 -0
  197. data/lib/expressir/commands/expand.rb +26 -0
  198. data/lib/expressir/commands/file_violations.rb +70 -0
  199. data/lib/expressir/commands/fix.rb +33 -0
  200. data/lib/expressir/commands/flatten.rb +29 -0
  201. data/lib/expressir/commands/format.rb +43 -0
  202. data/lib/expressir/commands/manifest.rb +420 -0
  203. data/lib/expressir/commands/mapping_validate.rb +68 -0
  204. data/lib/expressir/commands/non_ascii_character.rb +49 -0
  205. data/lib/expressir/commands/non_ascii_violation_collection.rb +301 -0
  206. data/lib/expressir/commands/package.rb +1222 -0
  207. data/lib/expressir/commands/parity_inputs.rb +160 -0
  208. data/lib/expressir/commands/validate.rb +106 -0
  209. data/lib/expressir/commands/validate_ascii.rb +94 -0
  210. data/lib/expressir/commands/validate_load.rb +91 -0
  211. data/lib/expressir/commands/version.rb +9 -0
  212. data/lib/expressir/commands/xsd.rb +23 -0
  213. data/lib/expressir/commands.rb +30 -0
  214. data/lib/expressir/config.rb +60 -0
  215. data/lib/expressir/coverage.rb +510 -0
  216. data/lib/expressir/eengine/arm_compare_report.rb +23 -0
  217. data/lib/expressir/eengine/changes_section.rb +16 -0
  218. data/lib/expressir/eengine/compare_report.rb +69 -0
  219. data/lib/expressir/eengine/mim_compare_report.rb +23 -0
  220. data/lib/expressir/eengine/modified_object.rb +21 -0
  221. data/lib/expressir/eengine.rb +9 -0
  222. data/lib/expressir/errors.rb +113 -0
  223. data/lib/expressir/express/adoc_hyperlink_formatter.rb +30 -0
  224. data/lib/expressir/express/adoc_source_formatter.rb +12 -0
  225. data/lib/expressir/express/ast_key_converter.rb +114 -0
  226. data/lib/expressir/express/builder.rb +277 -0
  227. data/lib/expressir/express/builder_context.rb +22 -0
  228. data/lib/expressir/express/builder_registry.rb +397 -0
  229. data/lib/expressir/express/builders/attribute_decl_builder.rb +32 -0
  230. data/lib/expressir/express/builders/built_in_builder.rb +75 -0
  231. data/lib/expressir/express/builders/constant_builder.rb +108 -0
  232. data/lib/expressir/express/builders/declaration_builder.rb +20 -0
  233. data/lib/expressir/express/builders/derive_clause_builder.rb +14 -0
  234. data/lib/expressir/express/builders/derived_attr_builder.rb +28 -0
  235. data/lib/expressir/express/builders/domain_rule_builder.rb +21 -0
  236. data/lib/expressir/express/builders/entity_decl_builder.rb +116 -0
  237. data/lib/expressir/express/builders/explicit_attr_builder.rb +49 -0
  238. data/lib/expressir/express/builders/expression_builder.rb +416 -0
  239. data/lib/expressir/express/builders/function_decl_builder.rb +86 -0
  240. data/lib/expressir/express/builders/helpers.rb +148 -0
  241. data/lib/expressir/express/builders/interface_builder.rb +151 -0
  242. data/lib/expressir/express/builders/inverse_attr_builder.rb +43 -0
  243. data/lib/expressir/express/builders/inverse_attr_type_builder.rb +30 -0
  244. data/lib/expressir/express/builders/inverse_clause_builder.rb +14 -0
  245. data/lib/expressir/express/builders/literal_builder.rb +93 -0
  246. data/lib/expressir/express/builders/procedure_decl_builder.rb +82 -0
  247. data/lib/expressir/express/builders/qualifier_builder.rb +102 -0
  248. data/lib/expressir/express/builders/reference_builder.rb +18 -0
  249. data/lib/expressir/express/builders/rule_decl_builder.rb +97 -0
  250. data/lib/expressir/express/builders/schema_body_decl_builder.rb +18 -0
  251. data/lib/expressir/express/builders/schema_decl_builder.rb +56 -0
  252. data/lib/expressir/express/builders/schema_version_builder.rb +34 -0
  253. data/lib/expressir/express/builders/simple_id_builder.rb +17 -0
  254. data/lib/expressir/express/builders/statement_builder.rb +243 -0
  255. data/lib/expressir/express/builders/subtype_constraint_builder.rb +166 -0
  256. data/lib/expressir/express/builders/syntax_builder.rb +30 -0
  257. data/lib/expressir/express/builders/type_builder.rb +238 -0
  258. data/lib/expressir/express/builders/type_decl_builder.rb +26 -0
  259. data/lib/expressir/express/builders/unique_clause_builder.rb +20 -0
  260. data/lib/expressir/express/builders/unique_rule_builder.rb +41 -0
  261. data/lib/expressir/express/builders/where_clause_builder.rb +20 -0
  262. data/lib/expressir/express/builders.rb +55 -0
  263. data/lib/expressir/express/cache.rb +76 -0
  264. data/lib/expressir/express/checker.rb +812 -0
  265. data/lib/expressir/express/concatenator.rb +79 -0
  266. data/lib/expressir/express/core.rb +95 -0
  267. data/lib/expressir/express/error.rb +124 -0
  268. data/lib/expressir/express/formatter.rb +149 -0
  269. data/lib/expressir/express/formatters/data_types_formatter.rb +362 -0
  270. data/lib/expressir/express/formatters/declarations_formatter.rb +753 -0
  271. data/lib/expressir/express/formatters/expressions_formatter.rb +180 -0
  272. data/lib/expressir/express/formatters/literals_formatter.rb +55 -0
  273. data/lib/expressir/express/formatters/references_formatter.rb +53 -0
  274. data/lib/expressir/express/formatters/remark_formatter.rb +270 -0
  275. data/lib/expressir/express/formatters/remark_item_formatter.rb +28 -0
  276. data/lib/expressir/express/formatters/statements_formatter.rb +272 -0
  277. data/lib/expressir/express/formatters/supertype_expressions_formatter.rb +54 -0
  278. data/lib/expressir/express/formatters.rb +22 -0
  279. data/lib/expressir/express/grammar/parser.rb +712 -0
  280. data/lib/expressir/express/grammar.rb +11 -0
  281. data/lib/expressir/express/hyperlink_formatter.rb +35 -0
  282. data/lib/expressir/express/interface_dot.rb +105 -0
  283. data/lib/expressir/express/lazy_repository.rb +211 -0
  284. data/lib/expressir/express/line_map.rb +48 -0
  285. data/lib/expressir/express/listing.rb +174 -0
  286. data/lib/expressir/express/model_traversal.rb +42 -0
  287. data/lib/expressir/express/model_visitor.rb +25 -0
  288. data/lib/expressir/express/node_position_index.rb +342 -0
  289. data/lib/expressir/express/parallel_files.rb +229 -0
  290. data/lib/expressir/express/parser.rb +523 -0
  291. data/lib/expressir/express/pretty_formatter.rb +586 -0
  292. data/lib/expressir/express/pretty_gate.rb +61 -0
  293. data/lib/expressir/express/refs_overlay.rb +47 -0
  294. data/lib/expressir/express/remark_attacher.rb +1098 -0
  295. data/lib/expressir/express/remark_overlay.rb +86 -0
  296. data/lib/expressir/express/remark_scanner.rb +245 -0
  297. data/lib/expressir/express/resolve_references_model_visitor.rb +29 -0
  298. data/lib/expressir/express/schema_block_scanner.rb +137 -0
  299. data/lib/expressir/express/schema_head_formatter.rb +22 -0
  300. data/lib/expressir/express/schema_plain_source_formatter.rb +11 -0
  301. data/lib/expressir/express/schema_source_formatter.rb +15 -0
  302. data/lib/expressir/express/scope_resolver.rb +223 -0
  303. data/lib/expressir/express/self_schema_reference.rb +126 -0
  304. data/lib/expressir/express/shtolo.rb +679 -0
  305. data/lib/expressir/express/smrl_xml.rb +125 -0
  306. data/lib/expressir/express/source_formatter.rb +15 -0
  307. data/lib/expressir/express/streaming_builder.rb +435 -0
  308. data/lib/expressir/express/xsd.rb +259 -0
  309. data/lib/expressir/express.rb +53 -0
  310. data/lib/expressir/liquid.rb +1 -0
  311. data/lib/expressir/manifest/resolver.rb +210 -0
  312. data/lib/expressir/manifest/validator.rb +192 -0
  313. data/lib/expressir/manifest.rb +6 -0
  314. data/lib/expressir/mapping/refpath.rb +857 -0
  315. data/lib/expressir/mapping.rb +253 -0
  316. data/lib/expressir/model/cache.rb +18 -0
  317. data/lib/expressir/model/concerns.rb +42 -0
  318. data/lib/expressir/model/data_types/aggregate.rb +26 -0
  319. data/lib/expressir/model/data_types/array.rb +25 -0
  320. data/lib/expressir/model/data_types/bag.rb +21 -0
  321. data/lib/expressir/model/data_types/binary.rb +19 -0
  322. data/lib/expressir/model/data_types/boolean.rb +15 -0
  323. data/lib/expressir/model/data_types/enumeration.rb +21 -0
  324. data/lib/expressir/model/data_types/enumeration_item.rb +24 -0
  325. data/lib/expressir/model/data_types/generic.rb +24 -0
  326. data/lib/expressir/model/data_types/generic_entity.rb +24 -0
  327. data/lib/expressir/model/data_types/integer.rb +15 -0
  328. data/lib/expressir/model/data_types/list.rb +23 -0
  329. data/lib/expressir/model/data_types/logical.rb +15 -0
  330. data/lib/expressir/model/data_types/number.rb +15 -0
  331. data/lib/expressir/model/data_types/real.rb +17 -0
  332. data/lib/expressir/model/data_types/select.rb +23 -0
  333. data/lib/expressir/model/data_types/set.rb +21 -0
  334. data/lib/expressir/model/data_types/string.rb +19 -0
  335. data/lib/expressir/model/data_types.rb +25 -0
  336. data/lib/expressir/model/declarations/attribute.rb +38 -0
  337. data/lib/expressir/model/declarations/constant.rb +28 -0
  338. data/lib/expressir/model/declarations/derived_attribute.rb +25 -0
  339. data/lib/expressir/model/declarations/entity.rb +62 -0
  340. data/lib/expressir/model/declarations/function.rb +59 -0
  341. data/lib/expressir/model/declarations/informal_proposition_rule.rb +25 -0
  342. data/lib/expressir/model/declarations/interface.rb +37 -0
  343. data/lib/expressir/model/declarations/interface_item.rb +21 -0
  344. data/lib/expressir/model/declarations/interfaced_item.rb +33 -0
  345. data/lib/expressir/model/declarations/inverse_attribute.rb +25 -0
  346. data/lib/expressir/model/declarations/parameter.rb +28 -0
  347. data/lib/expressir/model/declarations/procedure.rb +57 -0
  348. data/lib/expressir/model/declarations/remark_item.rb +21 -0
  349. data/lib/expressir/model/declarations/rule.rb +66 -0
  350. data/lib/expressir/model/declarations/schema.rb +215 -0
  351. data/lib/expressir/model/declarations/schema_version.rb +19 -0
  352. data/lib/expressir/model/declarations/schema_version_item.rb +19 -0
  353. data/lib/expressir/model/declarations/subtype_constraint.rb +32 -0
  354. data/lib/expressir/model/declarations/type.rb +45 -0
  355. data/lib/expressir/model/declarations/unique_rule.rb +26 -0
  356. data/lib/expressir/model/declarations/variable.rb +28 -0
  357. data/lib/expressir/model/declarations/where_rule.rb +26 -0
  358. data/lib/expressir/model/declarations.rb +31 -0
  359. data/lib/expressir/model/dependency_resolver.rb +268 -0
  360. data/lib/expressir/model/exp_file.rb +42 -0
  361. data/lib/expressir/model/expressions/aggregate_initializer.rb +18 -0
  362. data/lib/expressir/model/expressions/aggregate_initializer_item.rb +20 -0
  363. data/lib/expressir/model/expressions/binary_expression.rb +59 -0
  364. data/lib/expressir/model/expressions/entity_constructor.rb +20 -0
  365. data/lib/expressir/model/expressions/function_call.rb +20 -0
  366. data/lib/expressir/model/expressions/interval.rb +29 -0
  367. data/lib/expressir/model/expressions/query_expression.rb +31 -0
  368. data/lib/expressir/model/expressions/unary_expression.rb +25 -0
  369. data/lib/expressir/model/expressions.rb +18 -0
  370. data/lib/expressir/model/identifier.rb +26 -0
  371. data/lib/expressir/model/indexes/entity_index.rb +103 -0
  372. data/lib/expressir/model/indexes/item_graph.rb +185 -0
  373. data/lib/expressir/model/indexes/reference_index.rb +148 -0
  374. data/lib/expressir/model/indexes/type_index.rb +149 -0
  375. data/lib/expressir/model/indexes.rb +12 -0
  376. data/lib/expressir/model/interface_validator.rb +384 -0
  377. data/lib/expressir/model/literals/binary.rb +17 -0
  378. data/lib/expressir/model/literals/integer.rb +17 -0
  379. data/lib/expressir/model/literals/logical.rb +21 -0
  380. data/lib/expressir/model/literals/real.rb +17 -0
  381. data/lib/expressir/model/literals/string.rb +20 -0
  382. data/lib/expressir/model/literals.rb +13 -0
  383. data/lib/expressir/model/model_element.rb +377 -0
  384. data/lib/expressir/model/references/attribute_reference.rb +19 -0
  385. data/lib/expressir/model/references/group_reference.rb +19 -0
  386. data/lib/expressir/model/references/index_reference.rb +23 -0
  387. data/lib/expressir/model/references/simple_reference.rb +21 -0
  388. data/lib/expressir/model/references.rb +12 -0
  389. data/lib/expressir/model/remark_format.rb +17 -0
  390. data/lib/expressir/model/remark_info.rb +92 -0
  391. data/lib/expressir/model/remark_placement.rb +42 -0
  392. data/lib/expressir/model/repository.rb +483 -0
  393. data/lib/expressir/model/repository_validator.rb +293 -0
  394. data/lib/expressir/model/search_engine.rb +551 -0
  395. data/lib/expressir/model/statements/alias.rb +31 -0
  396. data/lib/expressir/model/statements/assignment.rb +23 -0
  397. data/lib/expressir/model/statements/case.rb +42 -0
  398. data/lib/expressir/model/statements/case_action.rb +20 -0
  399. data/lib/expressir/model/statements/compound.rb +21 -0
  400. data/lib/expressir/model/statements/escape.rb +18 -0
  401. data/lib/expressir/model/statements/if.rb +26 -0
  402. data/lib/expressir/model/statements/null.rb +18 -0
  403. data/lib/expressir/model/statements/procedure_call.rb +22 -0
  404. data/lib/expressir/model/statements/repeat.rb +40 -0
  405. data/lib/expressir/model/statements/return.rb +20 -0
  406. data/lib/expressir/model/statements/skip.rb +18 -0
  407. data/lib/expressir/model/statements.rb +20 -0
  408. data/lib/expressir/model/supertype_expressions/binary_supertype_expression.rb +25 -0
  409. data/lib/expressir/model/supertype_expressions/oneof_supertype_expression.rb +17 -0
  410. data/lib/expressir/model/supertype_expressions.rb +12 -0
  411. data/lib/expressir/model.rb +39 -0
  412. data/lib/expressir/package/builder.rb +231 -0
  413. data/lib/expressir/package/metadata.rb +79 -0
  414. data/lib/expressir/package/reader.rb +149 -0
  415. data/lib/expressir/package.rb +8 -0
  416. data/lib/expressir/schema_manifest.rb +159 -0
  417. data/lib/expressir/schema_manifest_entry.rb +15 -0
  418. data/lib/expressir/version.rb +8 -0
  419. data/lib/expressir.rb +94 -0
  420. data/lib/tasks/verify_remarks.rake +16 -0
  421. data/rakelib/native.rake +24 -0
  422. data/rakelib/oracle.rake +52 -0
  423. data/rakelib/verify_remarks.rake +16 -0
  424. metadata +690 -0
@@ -0,0 +1,523 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest"
4
+ require "json"
5
+ require "parsanol"
6
+
7
+ module Expressir
8
+ module Express
9
+ # Public-facing parser facade.
10
+ #
11
+ # Three concerns were split out (TODO.bugs/09):
12
+ # - Grammar rules → {Grammar::Parser} (~250 Parsanol rules)
13
+ # - Schema-block splitting → {SchemaBlockScanner}
14
+ # - I/O orchestration → this class (from_file, from_exp, etc.)
15
+ #
16
+ # The facade delegates grammar work to Grammar::Parser and block
17
+ # extraction to SchemaBlockScanner. All public methods remain
18
+ # backward-compatible.
19
+ class Parser
20
+ # Threshold for using memory-bounded fresh parse (bytes)
21
+ LARGE_FILE_THRESHOLD = 1024 * 1024 # 1 MB
22
+
23
+ class << self
24
+ # Delegate grammar-level queries to Grammar::Parser.
25
+ def native_available? = Grammar::Parser.native_available?
26
+ def cached_parser = Grammar::Parser.cached_parser
27
+ def cached_grammar_json = Grammar::Parser.cached_grammar_json
28
+ def cached_schema_grammar_json = Grammar::Parser.cached_schema_grammar_json
29
+ def parse_native(source) = Grammar::Parser.parse_native(source)
30
+ def clear_parser_cache = Grammar::Parser.clear_parser_cache
31
+ end
32
+
33
+ # UTF-8 BOM byte sequence (EF BB BF). Some editors prepend this
34
+ # to EXPRESS files; the parser fails because SCHEMA isn't at byte 0.
35
+ def self.strip_bom(source)
36
+ bytes = source.b
37
+ return source unless bytes.bytesize >= 3 &&
38
+ bytes.getbyte(0) == 0xEF &&
39
+ bytes.getbyte(1) == 0xBB &&
40
+ bytes.getbyte(2) == 0xBF
41
+
42
+ bytes.byteslice(3..).force_encoding(source.encoding)
43
+ end
44
+ private_class_method :strip_bom
45
+
46
+ # Parses Express file into an Express model.
47
+ # @param file [String] Express file path
48
+ # @param skip_references [Boolean] skip resolving references
49
+ # @param include_source [Boolean] attach original source code to model elements
50
+ # @param use_native [Boolean] use native parser (default: true when available)
51
+ # @param use_core [Boolean] use the Rust core parse path
52
+ # (default: true when the expressir-core extension is available;
53
+ # produces a byte-identical model to the Ruby path — see
54
+ # parser_core_parity_spec)
55
+ # @return [Model::ExpFile] ExpFile containing parsed schemas
56
+ # @raise [Error::SchemaParseFailure] if the schema file fails to parse
57
+ def self.from_file(file, skip_references: nil, include_source: nil,
58
+ root_path: nil, use_native: nil,
59
+ use_core: nil) # rubocop:disable Metrics/AbcSize
60
+ use_core = Core::NATIVE_AVAILABLE if use_core.nil?
61
+ if use_core && Core::NATIVE_AVAILABLE
62
+ return from_file_core(file, skip_references: skip_references,
63
+ include_source: include_source,
64
+ root_path: root_path)
65
+ end
66
+
67
+ Expressir::Benchmark.measure_file(file) do
68
+ source = strip_bom(File.read(file))
69
+
70
+ schema_file = root_path ? Pathname.new(file.to_s).relative_path_from(root_path).to_s : file.to_s
71
+
72
+ use_native = Grammar::Parser.native_available? if use_native.nil?
73
+
74
+ begin
75
+ ast = if use_native && Grammar::Parser.native_available?
76
+ begin
77
+ Grammar::Parser.parse_native(source)
78
+ rescue StandardError
79
+ Grammar::Parser.cached_parser.parse source
80
+ end
81
+ else
82
+ Grammar::Parser.cached_parser.parse source
83
+ end
84
+ rescue Parsanol::ParseFailed => e
85
+ raise Error::SchemaParseFailure.new(schema_file, e)
86
+ end
87
+
88
+ exp_file = ::Expressir::Express::Builder.build_with_remarks(ast, source: source,
89
+ include_source: include_source)
90
+
91
+ transfer_header_to_schema(exp_file, source)
92
+
93
+ exp_file.path = schema_file
94
+ exp_file.schemas.each do |schema|
95
+ schema.file = schema_file
96
+ schema.file_basename = File.basename(schema_file, ".exp")
97
+ end
98
+
99
+ unless skip_references
100
+ Expressir::Benchmark.measure_references do
101
+ ResolveReferencesModelVisitor.new.visit(exp_file)
102
+ end
103
+ end
104
+
105
+ exp_file
106
+ end
107
+ end
108
+
109
+ # Parses Express files into an Express model.
110
+ # @param files [Array<String>] Express file paths
111
+ # @param skip_references [Boolean] skip resolving references
112
+ # @param include_source [Boolean] attach original source code to model elements
113
+ # @param use_native [Boolean] use native parser (default: true when available)
114
+ # @yield [filename, schemas, error] Optional block called for each file
115
+ # @return [Model::Repository] Repository containing all parsed ExpFiles
116
+ def self.from_files(files, skip_references: nil, include_source: nil,
117
+ root_path: nil, use_native: nil, max_processes: nil,
118
+ compiled_set: nil, &progress)
119
+ set_path = compiled_set || ENV.fetch("EXPRESSIR_COMPILED_SET", nil)
120
+ if set_path && core_set_available?
121
+ repo = from_compiled_set(set_path, files,
122
+ skip_references: skip_references,
123
+ include_source: include_source,
124
+ root_path: root_path)
125
+ return repo if repo
126
+ end
127
+
128
+ # EXPRESSIR_BATCH=0 escapes the native batch workers: their
129
+ # Rust threads crash the process under some loads (SIGILL in
130
+ # the mpmc recv park — see GH batch-crash report); sequential
131
+ # parsing is slower but proven stable.
132
+ batch_disabled = ENV["EXPRESSIR_BATCH"] == "0"
133
+ all_exp_files = if batch_available? && !batch_disabled && files.size > 1
134
+ from_files_batch(
135
+ files, include_source: include_source,
136
+ root_path: root_path,
137
+ max_processes: max_processes,
138
+ compiled_set_out: set_path
139
+ ) do |file, exp_file, error|
140
+ progress&.call(file, exp_file&.schemas, error)
141
+ end
142
+ elsif ParallelFiles.sequential?(files, max_processes)
143
+ parse_files_sequentially(
144
+ files, skip_references: skip_references, include_source: include_source,
145
+ root_path: root_path, use_native: use_native
146
+ ) do |file, exp_file, error|
147
+ progress&.call(file, exp_file&.schemas, error)
148
+ end
149
+ else
150
+ ParallelFiles.run(
151
+ files,
152
+ max_processes: max_processes,
153
+ parse: lambda do |file|
154
+ from_file(file, skip_references: true, root_path: root_path,
155
+ use_native: use_native)
156
+ end,
157
+ ) do |file, exp_file, error|
158
+ progress&.call(file, exp_file&.schemas, error)
159
+ end
160
+ end
161
+
162
+ repository = build_repository(all_exp_files, skip_references: skip_references)
163
+ if set_path && !skip_references && !File.exist?(set_path) &&
164
+ !all_exp_files.include?(nil)
165
+ if core_set_available?
166
+ write_compiled_set(set_path, files, all_exp_files, root_path)
167
+ else
168
+ warn "expressir: compiled-set write to #{set_path} skipped: " \
169
+ "the expressir-core native extension is unavailable"
170
+ end
171
+ end
172
+ if set_path && !skip_references && File.exist?(set_path)
173
+ files = all_exp_files.compact
174
+ RefsOverlay.write(set_path, files)
175
+ graph = Model::Indexes::ItemGraph.new(repository)
176
+ repository.item_graph = graph
177
+ require "json"
178
+ File.write("#{set_path}.graph.json", JSON.generate(graph.tables))
179
+ end
180
+
181
+ repository
182
+ end
183
+
184
+ # Core path: the Rust extension parses and emits the model hash
185
+ # directly (lutaml wire shape); Ruby hydrates, then remark
186
+ # attachment runs on the source as usual.
187
+ def self.from_file_core(file, skip_references: nil,
188
+ include_source: nil, root_path: nil, &block)
189
+ unless Core::NATIVE_AVAILABLE
190
+ raise Error::StreamingUnsupportedError,
191
+ "core parse requires the native extension"
192
+ end
193
+
194
+ Expressir::Benchmark.measure_file(file) do
195
+ source = strip_bom(File.read(file))
196
+ schema_file = root_path ? Pathname.new(file.to_s).relative_path_from(root_path).to_s : file.to_s
197
+
198
+ exp_file =
199
+ begin
200
+ Core.parse_to_model(source, schema_file).tap(&:wire_parents)
201
+ rescue NotImplementedError
202
+ begin
203
+ Model::ExpFile.from_hash(
204
+ Core.parse_to_model_hash(source, schema_file),
205
+ )&.tap(&:wire_parents)
206
+ rescue StandardError => e
207
+ raise Error::SchemaParseFailure.new(schema_file, e)
208
+ end
209
+ rescue StandardError => e
210
+ raise Error::SchemaParseFailure.new(schema_file, e)
211
+ end
212
+
213
+ finalize_loaded_file(exp_file, source, schema_file,
214
+ include_source: include_source)
215
+
216
+ unless skip_references
217
+ Expressir::Benchmark.measure_references do
218
+ ResolveReferencesModelVisitor.new.visit(exp_file)
219
+ end
220
+ end
221
+
222
+ exp_file
223
+ end
224
+ end
225
+ private_class_method :from_file_core
226
+
227
+ # Shared post-parse steps for every core-path file: remark
228
+ # attachment, header-remark transfer, and path wiring.
229
+ def self.finalize_loaded_file(exp_file, source, schema_file,
230
+ include_source: nil)
231
+ RemarkAttacher.new(source).attach(exp_file) if source && include_source != false
232
+
233
+ transfer_header_to_schema(exp_file, source)
234
+
235
+ exp_file.path = schema_file
236
+ exp_file.schemas.each do |schema|
237
+ schema.file = schema_file
238
+ schema.file_basename = File.basename(schema_file, ".exp")
239
+ end
240
+ end
241
+ private_class_method :finalize_loaded_file
242
+
243
+ # Whether the native batch compiler is usable: the extension is
244
+ # loaded and exposes BatchStream.
245
+ def self.batch_available?
246
+ Core::NATIVE_AVAILABLE &&
247
+ ::Expressir::Core.const_defined?(:BatchStream, false)
248
+ end
249
+ private_class_method :batch_available?
250
+
251
+ # Whether the compiled-set artifact APIs are exposed.
252
+ def self.core_set_available?
253
+ Core::NATIVE_AVAILABLE && ::Expressir::Core.const_defined?(:Set, false)
254
+ end
255
+
256
+ # Concurrent core-path parse: workers compile in the background
257
+ # while this thread hydrates, attaches remarks, and reports
258
+ # progress per file. Results keep the input order; a file that
259
+ # fails to parse is nil-padded exactly like the other paths.
260
+ def self.from_files_batch(files, include_source: nil, root_path: nil,
261
+ max_processes: nil, compiled_set_out: nil,
262
+ &progress)
263
+ schema_file_for = lambda do |file|
264
+ root_path ? Pathname.new(file.to_s).relative_path_from(root_path).to_s : file.to_s
265
+ end
266
+ wire_paths = files.map { |f| schema_file_for.call(f) }
267
+ physical = wire_paths.zip(files.map(&:to_s)).to_h
268
+
269
+ results = {}
270
+ jobs = files.map { |f| [f.to_s, schema_file_for.call(f)] }
271
+ # Outcomes arrive in completion order; files are finalized and
272
+ # reported in input order (the contract every other path keeps).
273
+ pending = {}
274
+ stream = ::Expressir::Core::BatchStream.start(jobs, max_processes.to_i)
275
+ cursor = 0
276
+ while (item = stream.next)
277
+ wire_path, model, error = item
278
+ if error
279
+ # Unreadable sources raise like every other path; parse
280
+ # failures nil-pad and report.
281
+ raise Errno::ENOENT, error if error.start_with?("read ")
282
+
283
+ pending[wire_path] = [nil, error]
284
+ else
285
+ pending[wire_path] = [model, nil]
286
+ end
287
+ while (entry = pending[wire_paths[cursor]])
288
+ pending.delete(wire_paths[cursor])
289
+ ordered_path = wire_paths[cursor]
290
+ file = physical[ordered_path]
291
+ loaded, load_error = entry
292
+ if loaded
293
+ source = strip_bom(File.read(file))
294
+ loaded.wire_parents
295
+ finalize_loaded_file(loaded, source, ordered_path,
296
+ include_source: include_source)
297
+ results[ordered_path] = loaded
298
+ yield(file, loaded, nil)
299
+ else
300
+ results[ordered_path] = nil
301
+ yield(file, nil,
302
+ Error::SchemaParseFailure.new(ordered_path,
303
+ RuntimeError.new(load_error)))
304
+ end
305
+ cursor += 1
306
+ end
307
+ end
308
+
309
+ if compiled_set_out && !results.value?(nil)
310
+ stream.write_set(compiled_set_out, physical,
311
+ Expressir::Version::VERSION)
312
+ RemarkOverlay.write(compiled_set_out, results.values.compact)
313
+ end
314
+
315
+ wire_paths.map { |wire_path| results[wire_path] }
316
+ end
317
+ private_class_method :from_files_batch
318
+
319
+ # Warm start from a compiled-set artifact. Returns nil (caller
320
+ # falls back to compiling) when the artifact is unreadable or no
321
+ # longer matches the sources. Remarks are re-attached from the
322
+ # source files and references are resolved as usual — everything
323
+ # not carried by the wire is deterministic and cheap to rebuild.
324
+ def self.from_compiled_set(path, files, skip_references: nil,
325
+ include_source: nil, root_path: nil, &progress)
326
+ schema_file_for = lambda do |file|
327
+ root_path ? Pathname.new(file.to_s).relative_path_from(root_path).to_s : file.to_s
328
+ end
329
+ physical = files.to_h { |f| [schema_file_for.call(f), f.to_s] }
330
+
331
+ set = begin
332
+ ::Expressir::Core::Set.open(path)
333
+ rescue StandardError
334
+ nil
335
+ end
336
+ return nil if set.nil?
337
+ return nil unless set.matches_sources(physical) == true
338
+
339
+ models = []
340
+ while (pair = set.next)
341
+ wire_path, model = pair
342
+ file = physical[wire_path]
343
+ # The artifact wire is pre-remark; the overlay carries them
344
+ # (plus header remarks and remark-derived structures), so the
345
+ # RemarkAttacher never runs on a warm load.
346
+ model.wire_parents
347
+ finalize_loaded_file(model, nil, wire_path,
348
+ include_source: include_source)
349
+ models << model
350
+ progress&.call(file || wire_path, model.schemas, nil)
351
+ end
352
+ RemarkOverlay.apply(path, models)
353
+
354
+ repository = build_repository(models, skip_references: true)
355
+ graph_path = "#{path}.graph.json"
356
+ if File.exist?(graph_path)
357
+ require "json"
358
+ repository.item_graph =
359
+ Model::Indexes::ItemGraph.from_tables(JSON.parse(File.read(graph_path)))
360
+ end
361
+ if skip_references || RefsOverlay.apply_to(path, models)
362
+ # Either explicitly skipping resolution or the compiled-set
363
+ # refs sidecar already re-bound the references.
364
+ else
365
+ Expressir::Benchmark.measure_references do
366
+ ResolveReferencesModelVisitor.new.visit(repository)
367
+ end
368
+ end
369
+ repository
370
+ end
371
+ private_class_method :from_compiled_set
372
+
373
+ def self.parse_files_sequentially(files, skip_references: nil,
374
+ include_source: nil, root_path: nil, use_native: nil, &block)
375
+ all_exp_files = []
376
+
377
+ files.each do |file|
378
+ exp_file = from_file(file, skip_references: true,
379
+ root_path: root_path, use_native: use_native)
380
+ all_exp_files << exp_file
381
+
382
+ yield(file, exp_file, nil) if block
383
+ rescue StandardError => e
384
+ # Nil-pad so results align with files by index, exactly like the
385
+ # parallel path does.
386
+ all_exp_files << nil if e.is_a?(Error::SchemaParseFailure)
387
+ yield(file, nil, e) if block
388
+ raise unless e.is_a?(Error::SchemaParseFailure)
389
+ end
390
+
391
+ all_exp_files
392
+ end
393
+
394
+ # Artifact write for the non-batch paths (single file,
395
+ # EXPRESSIR_BATCH=0, small sequential sets): serializes the
396
+ # parsed models through Core.write_set, producing the same
397
+ # artifact shape the batch path writes natively. The wire is
398
+ # pre-remark — RemarkOverlay.write carries the remark-derived
399
+ # attributes, exactly as it does for the batch path.
400
+ def self.write_compiled_set(set_path, files, exp_files, root_path)
401
+ require "digest"
402
+ require "json"
403
+ schema_file_for = lambda do |file|
404
+ root_path ? Pathname.new(file.to_s).relative_path_from(root_path).to_s : file.to_s
405
+ end
406
+ entries = files.zip(exp_files).map do |file, exp_file|
407
+ [schema_file_for.call(file),
408
+ Digest::SHA256.file(file.to_s).hexdigest,
409
+ JSON.generate(strip_remark_wire(exp_file.to_hash))]
410
+ end
411
+ ::Expressir::Core.write_set(set_path, entries, Expressir::Version::VERSION)
412
+ RemarkOverlay.write(set_path, exp_files)
413
+ end
414
+ private_class_method :write_compiled_set
415
+
416
+ # Deep copy of a serialized model without the RemarkOverlay
417
+ # attributes: the artifact wire carries only the parsed model;
418
+ # untagged remarks are plain hashes that the Rust hydrator
419
+ # cannot instantiate, and every remark-derived value belongs to
420
+ # the overlay anyway.
421
+ def self.strip_remark_wire(node)
422
+ case node
423
+ when Hash
424
+ node.each_with_object({}) do |(key, value), out|
425
+ out[key] = strip_remark_wire(value) unless RemarkOverlay::CAPTURED.include?(key)
426
+ end
427
+ when Array
428
+ node.map { |value| strip_remark_wire(value) }
429
+ else
430
+ node
431
+ end
432
+ end
433
+ private_class_method :strip_remark_wire
434
+
435
+ def self.build_repository(all_exp_files, skip_references: nil)
436
+ repository = Model::Repository.new(files: all_exp_files)
437
+
438
+ unless skip_references
439
+ Expressir::Benchmark.measure_references do
440
+ ResolveReferencesModelVisitor.new.visit(repository)
441
+ end
442
+ end
443
+
444
+ repository
445
+ end
446
+
447
+ # Parses Express content string into an Express model.
448
+ # @param content [String] EXPRESS source code
449
+ # @param skip_references [Boolean] skip resolving references
450
+ # @param include_source [Boolean] attach original source code to model elements
451
+ # @param use_native [Boolean] use native parser (default: true when available)
452
+ # @param use_streaming [Boolean] unsupported on current parsanol;
453
+ # passing true raises {Error::StreamingUnsupportedError}. The
454
+ # streaming paths return when parsanol exposes a stable
455
+ # parse_with_builder (see parsanol-ruby#52 and the TODO.max-perf/02
456
+ # notes).
457
+ # @return [Model::ExpFile] Parsed ExpFile
458
+ # @raise [Error::SchemaParseFailure] if the content fails to parse
459
+ def self.from_exp(content, skip_references: nil, include_source: nil,
460
+ use_native: nil, use_streaming: false)
461
+ content = strip_bom(content)
462
+ if use_streaming
463
+ raise Error::StreamingUnsupportedError
464
+ end
465
+
466
+ use_native = Grammar::Parser.native_available? if use_native.nil?
467
+
468
+ begin
469
+ ast = if use_native && Grammar::Parser.native_available?
470
+ Grammar::Parser.parse_native(content)
471
+ else
472
+ Grammar::Parser.cached_parser.parse(content)
473
+ end
474
+ rescue Parsanol::ParseFailed, StandardError => e
475
+ raise Error::SchemaParseFailure.new("(from string)", e)
476
+ end
477
+
478
+ exp_file = ::Expressir::Express::Builder.build_with_remarks(ast,
479
+ source: content,
480
+ include_source: include_source)
481
+
482
+ transfer_header_to_schema(exp_file, content)
483
+
484
+ exp_file.schemas.each do |schema|
485
+ schema.file = nil
486
+ schema.file_basename = nil
487
+ end
488
+
489
+ unless skip_references
490
+ Expressir::Benchmark.measure_references do
491
+ ResolveReferencesModelVisitor.new.visit(exp_file)
492
+ end
493
+ end
494
+
495
+ exp_file
496
+ end
497
+
498
+ # Transfer file-level untagged remarks that appear before the first
499
+ # SCHEMA keyword to the first schema's +header+ attribute so they are
500
+ # accessible via +schema.header+ and through Liquid drops.
501
+ def self.transfer_header_to_schema(exp_file, source = nil)
502
+ return unless exp_file.untagged_remarks&.any?
503
+ return unless exp_file.schemas&.any?
504
+ return unless source
505
+
506
+ schema_pos = source.b.index(/\bSCHEMA\b/)
507
+ return unless schema_pos
508
+
509
+ header_remarks = exp_file.untagged_remarks.select do |r|
510
+ r.source_offset && r.source_offset < schema_pos
511
+ end
512
+ return unless header_remarks.any?
513
+
514
+ header_text = header_remarks.map(&:text).join("\n")
515
+ exp_file.schemas.first.header = header_text
516
+ exp_file.untagged_remarks -= header_remarks
517
+ end
518
+ private_class_method :transfer_header_to_schema
519
+ private_class_method :parse_files_sequentially
520
+ private_class_method :build_repository
521
+ end
522
+ end
523
+ end