expressir 1.2.11-aarch64-linux → 2.4.29-aarch64-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.
- checksums.yaml +4 -4
- data/.cargo/config.toml +3 -0
- data/.github/scripts/test_installed_gem.rb +34 -0
- data/.github/workflows/codeql.yml +35 -0
- data/.github/workflows/docs.yml +99 -0
- data/.github/workflows/links.yml +100 -0
- data/.github/workflows/native-gems.yml +201 -0
- data/.github/workflows/rake.yml +10 -296
- data/.github/workflows/release.yml +26 -114
- data/.github/workflows/rust-ext.yml +41 -0
- data/.github/workflows/stress.yml +36 -0
- data/.github/workflows/validate_schemas.yml +48 -0
- data/.github/workflows/verify_remarks.yml +33 -0
- data/.gitignore +33 -1
- data/.rubocop.yml +11 -11
- data/.rubocop_todo.yml +297 -0
- data/CHANGELOG.md +159 -0
- data/Gemfile +15 -1
- data/README.adoc +2675 -47
- data/Rakefile +34 -10
- data/TODO.bugs/01-stale-transformer-autoload.md +39 -0
- data/TODO.bugs/02-parser-class-instance-vars.md +36 -0
- data/TODO.bugs/03-builder-mutable-state.md +43 -0
- data/TODO.bugs/04-formatter-public-send-dispatch.md +53 -0
- data/TODO.bugs/05-anonymous-formatter-subclass.md +45 -0
- data/TODO.bugs/06-collection-registry-single-source.md +53 -0
- data/TODO.bugs/07-require-relative-cleanup.md +42 -0
- data/TODO.bugs/08-require-expressir-in-commands.md +34 -0
- data/TODO.bugs/09-parser-split.md +53 -0
- data/TODO.bugs/10-to-s-override.md +42 -0
- data/TODO.bugs/11-parser-class-variables.md +39 -0
- data/TODO.bugs/12-marker-modules-vs-registry.md +64 -0
- data/TODO.bugs/13-string-literal-scanner-limitation.md +52 -0
- data/TODO.bugs/14-model-formatting-leak.md +30 -0
- data/TODO.bugs/15-expression-children-macro.md +27 -0
- data/TODO.bugs/16-pretty-formatter-duplication.md +28 -0
- data/TODO.bugs/17-snake-case-cache-mutable-constant.md +28 -0
- data/TODO.bugs/18-const-get-private-constants.md +30 -0
- data/TODO.bugs/19-format-methods-public.md +22 -0
- data/TODO.bugs/20-coverage-nested-entities-dedup.md +20 -0
- data/TODO.bugs/21-operator-tokens-secondary-dispatch.md +21 -0
- data/TODO.bugs/22-builder-fast-path-wrappers.md +32 -0
- data/TODO.bugs/23-coverage-inverse-maps.md +21 -0
- data/TODO.bugs/24-streaming-builder-complexity.md +19 -0
- data/TODO.bugs/25-debug-puts-in-production.md +21 -0
- data/TODO.bugs/26-generic-entity-children-misplaced.md +21 -0
- data/TODO.bugs/27-package-build-god-method.md +19 -0
- data/TODO.bugs/28-package-god-class.md +30 -0
- data/TODO.bugs/29-validate-ascii-god-class.md +24 -0
- data/TODO.bugs/30-unicode-map-extraction.md +19 -0
- data/TODO.bugs/README.md +43 -0
- data/TODO.max-perf/01-restore-ci-green.md +36 -0
- data/TODO.max-perf/02-streaming-parse-path.md +31 -0
- data/TODO.max-perf/03-cli-parallel-opt-in.md +27 -0
- data/TODO.max-perf/04-benchmark-harness.md +28 -0
- data/TODO.max-perf/05-parallel-fidelity-specs.md +22 -0
- data/TODO.max-perf/06-builder-cpu-audit.md +41 -0
- data/TODO.max-perf/07-upstream-parsanol-roadmap.md +27 -0
- data/TODO.max-perf/08-builder-build-perf.md +45 -0
- data/TODO.max-perf/09-grammar-cold-start.md +25 -0
- data/TODO.max-perf/10-parser-facade-hygiene.md +23 -0
- data/TODO.max-perf/11-ci-green-closeout.md +25 -0
- data/TODO.max-perf/12-require-boot-profile.md +25 -0
- data/TODO.max-perf/13-key-conversion-specs.md +26 -0
- data/TODO.max-perf/14-builder-call-handler-audit.md +28 -0
- data/TODO.parity-ee/00-overview.md +76 -0
- data/TODO.parity-ee/01-annex-g-rule-extraction.md +41 -0
- data/TODO.parity-ee/02-eeng-algorithm-inventory.md +8 -0
- data/TODO.parity-ee/03-eeng-oracle-harness.md +33 -0
- data/TODO.parity-ee/04-shtolo-concatenate.md +44 -0
- data/TODO.parity-ee/05-shtolo-longform-flatten.md +53 -0
- data/TODO.parity-ee/06-interface-scheduling-parity.md +47 -0
- data/TODO.parity-ee/07-semantic-checks-port.md +35 -0
- data/TODO.parity-ee/08-pretty-roundtrip-gate.md +27 -0
- data/TODO.parity-ee/09-smrl-index-and-listing.md +22 -0
- data/TODO.parity-ee/10-interface-dot-graph.md +21 -0
- data/TODO.parity-ee/11-import-eeng-tests.md +79 -0
- data/TODO.parity-ee/12-full-check-catalog.md +67 -0
- data/TODO.parity-ee/13-population-p21.md +54 -0
- data/TODO.parity-ee/14-shtolo-completion.md +44 -0
- data/TODO.parity-ee/15-part28-xml.md +51 -0
- data/TODO.parity-ee/16-compare-patch.md +48 -0
- data/TODO.parity-ee/17-official-tests.md +42 -0
- data/TODO.parity-ee/18-mim-mapping.md +47 -0
- data/TODO.parity-ee/19-architecture.md +97 -0
- data/TODO.parity-ee/parity-matrix.md +108 -0
- data/TODO.refpath-v2/00-overview.md +64 -0
- data/TODO.suma-improvements/00-overview.md +23 -0
- data/TODO.suma-improvements/01-prebuilt-platform-gems.md +33 -0
- data/TODO.suma-improvements/02-suma-e2e.md +39 -0
- data/TODO.suma-improvements/03-item-graph.md +22 -0
- data/TODO.suma-improvements/04-compiled-set-default.md +16 -0
- data/TODO.suma-improvements/05-validation-in-docs.md +17 -0
- data/TODO.suma-improvements/06-memory-remeasure.md +36 -0
- data/TODO.suma-improvements/07-part28-xml.md +15 -0
- data/TODO.suma-improvements/08-windows-gnu-toolchain.md +15 -0
- data/TODO.suma-improvements/09-checker-tranche3.md +13 -0
- data/TODO.suma-improvements/10-expressdoc.md +8 -0
- data/benchmark/srl_benchmark.rb +458 -0
- data/benchmark/srl_native_benchmark.rb +146 -0
- data/benchmark/srl_ruby_benchmark.rb +132 -0
- data/bin/rspec +2 -1
- data/docs/Gemfile +12 -0
- data/docs/_config.yml +141 -0
- data/docs/_guides/changes/changes-format.adoc +778 -0
- data/docs/_guides/changes/importing-eengine.adoc +898 -0
- data/docs/_guides/changes/index.adoc +396 -0
- data/docs/_guides/changes/programmatic-usage.adoc +1038 -0
- data/docs/_guides/changes/validating-changes.adoc +681 -0
- data/docs/_guides/cli/benchmark-performance.adoc +834 -0
- data/docs/_guides/cli/coverage-analysis.adoc +921 -0
- data/docs/_guides/cli/format-schemas.adoc +547 -0
- data/docs/_guides/cli/index.adoc +8 -0
- data/docs/_guides/cli/managing-changes.adoc +927 -0
- data/docs/_guides/cli/validate-ascii.adoc +645 -0
- data/docs/_guides/cli/validate-schemas.adoc +534 -0
- data/docs/_guides/formatter/formatter-architecture.adoc +401 -0
- data/docs/_guides/index.adoc +165 -0
- data/docs/_guides/ler/creating-packages.adoc +664 -0
- data/docs/_guides/ler/index.adoc +305 -0
- data/docs/_guides/ler/loading-packages.adoc +707 -0
- data/docs/_guides/ler/package-formats.adoc +748 -0
- data/docs/_guides/ler/querying-packages.adoc +826 -0
- data/docs/_guides/ler/step-packages.adoc +385 -0
- data/docs/_guides/ler/validating-packages.adoc +750 -0
- data/docs/_guides/liquid/basic-templates.adoc +813 -0
- data/docs/_guides/liquid/documentation-generation.adoc +1042 -0
- data/docs/_guides/liquid/drops-reference.adoc +829 -0
- data/docs/_guides/liquid/filters-and-tags.adoc +912 -0
- data/docs/_guides/liquid/index.adoc +468 -0
- data/docs/_guides/manifests/creating-manifests.adoc +483 -0
- data/docs/_guides/manifests/index.adoc +307 -0
- data/docs/_guides/manifests/resolving-manifests.adoc +557 -0
- data/docs/_guides/manifests/validating-manifests.adoc +713 -0
- data/docs/_guides/ruby-api/formatting-schemas.adoc +605 -0
- data/docs/_guides/ruby-api/index.adoc +257 -0
- data/docs/_guides/ruby-api/parsing-files.adoc +421 -0
- data/docs/_guides/ruby-api/search-engine.adoc +609 -0
- data/docs/_guides/ruby-api/working-with-repository.adoc +577 -0
- data/docs/_pages/data-model.adoc +665 -0
- data/docs/_pages/express-language.adoc +506 -0
- data/docs/_pages/getting-started.adoc +414 -0
- data/docs/_pages/index.adoc +116 -0
- data/docs/_pages/introduction.adoc +256 -0
- data/docs/_pages/ler-packages.adoc +837 -0
- data/docs/_pages/parsers.adoc +709 -0
- data/docs/_pages/schema-manifests.adoc +431 -0
- data/docs/_references/index.adoc +228 -0
- data/docs/_tutorials/creating-ler-package.adoc +735 -0
- data/docs/_tutorials/documentation-coverage.adoc +795 -0
- data/docs/_tutorials/formatting-schemas.adoc +89 -0
- data/docs/_tutorials/index.adoc +231 -0
- data/docs/_tutorials/liquid-templates.adoc +806 -0
- data/docs/_tutorials/parsing-your-first-schema.adoc +522 -0
- data/docs/_tutorials/querying-schemas.adoc +751 -0
- data/docs/_tutorials/working-with-multiple-schemas.adoc +676 -0
- data/docs/index.adoc +242 -0
- data/docs/lychee.toml +90 -0
- data/examples/demo_ler_usage.sh +86 -0
- data/examples/ler/README.md +111 -0
- data/examples/ler/simple_example.ler +0 -0
- data/examples/ler/simple_schema.exp +33 -0
- data/examples/ler_build.rb +75 -0
- data/examples/ler_cli.rb +79 -0
- data/examples/ler_demo_complete.rb +276 -0
- data/examples/ler_query.rb +91 -0
- data/examples/ler_query_examples.rb +305 -0
- data/examples/ler_stats.rb +81 -0
- data/examples/phase3_demo.rb +159 -0
- data/examples/query_demo_simple.rb +131 -0
- data/exe/expressir +6 -17
- data/exe/expressir-format +14 -0
- data/exe/{format-test → expressir-format-test} +8 -7
- data/expressir.gemspec +50 -37
- data/lib/expressir/3.2/expressir_core.so +0 -0
- data/lib/expressir/3.3/expressir_core.so +0 -0
- data/lib/expressir/3.4/expressir_core.so +0 -0
- data/lib/expressir/4.0/expressir_core.so +0 -0
- data/lib/expressir/benchmark.rb +310 -0
- data/lib/expressir/changes/item_change.rb +20 -0
- data/lib/expressir/changes/mapping_change.rb +16 -0
- data/lib/expressir/changes/schema_change.rb +85 -0
- data/lib/expressir/changes/version_change.rb +26 -0
- data/lib/expressir/changes.rb +9 -0
- data/lib/expressir/cli.rb +138 -11
- data/lib/expressir/commands/base.rb +25 -0
- data/lib/expressir/commands/benchmark.rb +59 -0
- data/lib/expressir/commands/benchmark_cache.rb +80 -0
- data/lib/expressir/commands/changes.rb +34 -0
- data/lib/expressir/commands/changes_import_eengine.rb +146 -0
- data/lib/expressir/commands/changes_validate.rb +63 -0
- data/lib/expressir/commands/check.rb +56 -0
- data/lib/expressir/commands/clean.rb +20 -0
- data/lib/expressir/commands/coverage.rb +458 -0
- data/lib/expressir/commands/expand.rb +26 -0
- data/lib/expressir/commands/file_violations.rb +70 -0
- data/lib/expressir/commands/fix.rb +33 -0
- data/lib/expressir/commands/flatten.rb +29 -0
- data/lib/expressir/commands/format.rb +43 -0
- data/lib/expressir/commands/manifest.rb +420 -0
- data/lib/expressir/commands/mapping_validate.rb +68 -0
- data/lib/expressir/commands/non_ascii_character.rb +49 -0
- data/lib/expressir/commands/non_ascii_violation_collection.rb +301 -0
- data/lib/expressir/commands/package.rb +1222 -0
- data/lib/expressir/commands/parity_inputs.rb +160 -0
- data/lib/expressir/commands/validate.rb +106 -0
- data/lib/expressir/commands/validate_ascii.rb +94 -0
- data/lib/expressir/commands/validate_load.rb +91 -0
- data/lib/expressir/commands/version.rb +9 -0
- data/lib/expressir/commands/xsd.rb +23 -0
- data/lib/expressir/commands.rb +30 -0
- data/lib/expressir/config.rb +40 -3
- data/lib/expressir/coverage.rb +510 -0
- data/lib/expressir/eengine/arm_compare_report.rb +23 -0
- data/lib/expressir/eengine/changes_section.rb +16 -0
- data/lib/expressir/eengine/compare_report.rb +69 -0
- data/lib/expressir/eengine/mim_compare_report.rb +23 -0
- data/lib/expressir/eengine/modified_object.rb +21 -0
- data/lib/expressir/eengine.rb +9 -0
- data/lib/expressir/errors.rb +113 -0
- data/lib/expressir/express/adoc_hyperlink_formatter.rb +30 -0
- data/lib/expressir/express/adoc_source_formatter.rb +12 -0
- data/lib/expressir/express/ast_key_converter.rb +114 -0
- data/lib/expressir/express/builder.rb +277 -0
- data/lib/expressir/express/builder_context.rb +22 -0
- data/lib/expressir/express/builder_registry.rb +397 -0
- data/lib/expressir/express/builders/attribute_decl_builder.rb +32 -0
- data/lib/expressir/express/builders/built_in_builder.rb +75 -0
- data/lib/expressir/express/builders/constant_builder.rb +108 -0
- data/lib/expressir/express/builders/declaration_builder.rb +20 -0
- data/lib/expressir/express/builders/derive_clause_builder.rb +14 -0
- data/lib/expressir/express/builders/derived_attr_builder.rb +28 -0
- data/lib/expressir/express/builders/domain_rule_builder.rb +21 -0
- data/lib/expressir/express/builders/entity_decl_builder.rb +116 -0
- data/lib/expressir/express/builders/explicit_attr_builder.rb +49 -0
- data/lib/expressir/express/builders/expression_builder.rb +416 -0
- data/lib/expressir/express/builders/function_decl_builder.rb +86 -0
- data/lib/expressir/express/builders/helpers.rb +148 -0
- data/lib/expressir/express/builders/interface_builder.rb +151 -0
- data/lib/expressir/express/builders/inverse_attr_builder.rb +43 -0
- data/lib/expressir/express/builders/inverse_attr_type_builder.rb +30 -0
- data/lib/expressir/express/builders/inverse_clause_builder.rb +14 -0
- data/lib/expressir/express/builders/literal_builder.rb +93 -0
- data/lib/expressir/express/builders/procedure_decl_builder.rb +82 -0
- data/lib/expressir/express/builders/qualifier_builder.rb +102 -0
- data/lib/expressir/express/builders/reference_builder.rb +18 -0
- data/lib/expressir/express/builders/rule_decl_builder.rb +97 -0
- data/lib/expressir/express/builders/schema_body_decl_builder.rb +18 -0
- data/lib/expressir/express/builders/schema_decl_builder.rb +56 -0
- data/lib/expressir/express/builders/schema_version_builder.rb +34 -0
- data/lib/expressir/express/builders/simple_id_builder.rb +17 -0
- data/lib/expressir/express/builders/statement_builder.rb +243 -0
- data/lib/expressir/express/builders/subtype_constraint_builder.rb +166 -0
- data/lib/expressir/express/builders/syntax_builder.rb +30 -0
- data/lib/expressir/express/builders/type_builder.rb +238 -0
- data/lib/expressir/express/builders/type_decl_builder.rb +26 -0
- data/lib/expressir/express/builders/unique_clause_builder.rb +20 -0
- data/lib/expressir/express/builders/unique_rule_builder.rb +41 -0
- data/lib/expressir/express/builders/where_clause_builder.rb +20 -0
- data/lib/expressir/express/builders.rb +55 -0
- data/lib/expressir/express/cache.rb +43 -18
- data/lib/expressir/express/checker.rb +812 -0
- data/lib/expressir/express/concatenator.rb +79 -0
- data/lib/expressir/express/core.rb +95 -0
- data/lib/expressir/express/error.rb +124 -0
- data/lib/expressir/express/formatter.rb +89 -1548
- data/lib/expressir/express/formatters/data_types_formatter.rb +362 -0
- data/lib/expressir/express/formatters/declarations_formatter.rb +753 -0
- data/lib/expressir/express/formatters/expressions_formatter.rb +180 -0
- data/lib/expressir/express/formatters/literals_formatter.rb +55 -0
- data/lib/expressir/express/formatters/references_formatter.rb +53 -0
- data/lib/expressir/express/formatters/remark_formatter.rb +270 -0
- data/lib/expressir/express/formatters/remark_item_formatter.rb +28 -0
- data/lib/expressir/express/formatters/statements_formatter.rb +272 -0
- data/lib/expressir/express/formatters/supertype_expressions_formatter.rb +54 -0
- data/lib/expressir/express/formatters.rb +22 -0
- data/lib/expressir/express/grammar/parser.rb +712 -0
- data/lib/expressir/express/grammar.rb +11 -0
- data/lib/expressir/express/hyperlink_formatter.rb +4 -5
- data/lib/expressir/express/interface_dot.rb +105 -0
- data/lib/expressir/express/lazy_repository.rb +211 -0
- data/lib/expressir/express/line_map.rb +48 -0
- data/lib/expressir/express/listing.rb +174 -0
- data/lib/expressir/express/model_traversal.rb +42 -0
- data/lib/expressir/express/model_visitor.rb +11 -10
- data/lib/expressir/express/node_position_index.rb +342 -0
- data/lib/expressir/express/parallel_files.rb +229 -0
- data/lib/expressir/express/parser.rb +501 -62
- data/lib/expressir/express/pretty_formatter.rb +586 -0
- data/lib/expressir/express/pretty_gate.rb +61 -0
- data/lib/expressir/express/refs_overlay.rb +47 -0
- data/lib/expressir/express/remark_attacher.rb +1098 -0
- data/lib/expressir/express/remark_overlay.rb +86 -0
- data/lib/expressir/express/remark_scanner.rb +245 -0
- data/lib/expressir/express/resolve_references_model_visitor.rb +7 -9
- data/lib/expressir/express/schema_block_scanner.rb +137 -0
- data/lib/expressir/express/schema_head_formatter.rb +4 -5
- data/lib/expressir/express/schema_plain_source_formatter.rb +11 -0
- data/lib/expressir/express/schema_source_formatter.rb +15 -0
- data/lib/expressir/express/scope_resolver.rb +223 -0
- data/lib/expressir/express/self_schema_reference.rb +126 -0
- data/lib/expressir/express/shtolo.rb +679 -0
- data/lib/expressir/express/smrl_xml.rb +125 -0
- data/lib/expressir/express/source_formatter.rb +15 -0
- data/lib/expressir/express/streaming_builder.rb +435 -0
- data/lib/expressir/express/xsd.rb +259 -0
- data/lib/expressir/express.rb +53 -0
- data/lib/expressir/liquid.rb +1 -0
- data/lib/expressir/manifest/resolver.rb +210 -0
- data/lib/expressir/manifest/validator.rb +192 -0
- data/lib/expressir/manifest.rb +6 -0
- data/lib/expressir/mapping/refpath.rb +857 -0
- data/lib/expressir/mapping.rb +253 -0
- data/lib/expressir/model/cache.rb +10 -9
- data/lib/expressir/model/concerns.rb +42 -0
- data/lib/expressir/model/data_types/aggregate.rb +8 -13
- data/lib/expressir/model/data_types/array.rb +15 -21
- data/lib/expressir/model/data_types/bag.rb +11 -15
- data/lib/expressir/model/data_types/binary.rb +9 -12
- data/lib/expressir/model/data_types/boolean.rb +7 -2
- data/lib/expressir/model/data_types/enumeration.rb +11 -15
- data/lib/expressir/model/data_types/enumeration_item.rb +5 -7
- data/lib/expressir/model/data_types/generic.rb +6 -8
- data/lib/expressir/model/data_types/generic_entity.rb +11 -13
- data/lib/expressir/model/data_types/integer.rb +7 -2
- data/lib/expressir/model/data_types/list.rb +13 -18
- data/lib/expressir/model/data_types/logical.rb +7 -2
- data/lib/expressir/model/data_types/number.rb +7 -2
- data/lib/expressir/model/data_types/real.rb +7 -9
- data/lib/expressir/model/data_types/select.rb +13 -18
- data/lib/expressir/model/data_types/set.rb +11 -15
- data/lib/expressir/model/data_types/string.rb +9 -12
- data/lib/expressir/model/data_types.rb +25 -0
- data/lib/expressir/model/declarations/attribute.rb +19 -28
- data/lib/expressir/model/declarations/constant.rb +10 -16
- data/lib/expressir/model/declarations/derived_attribute.rb +25 -0
- data/lib/expressir/model/declarations/entity.rb +39 -30
- data/lib/expressir/model/declarations/function.rb +32 -40
- data/lib/expressir/model/declarations/informal_proposition_rule.rb +25 -0
- data/lib/expressir/model/declarations/interface.rb +25 -16
- data/lib/expressir/model/declarations/interface_item.rb +9 -11
- data/lib/expressir/model/declarations/interfaced_item.rb +15 -19
- data/lib/expressir/model/declarations/inverse_attribute.rb +25 -0
- data/lib/expressir/model/declarations/parameter.rb +10 -16
- data/lib/expressir/model/declarations/procedure.rb +30 -37
- data/lib/expressir/model/declarations/remark_item.rb +11 -11
- data/lib/expressir/model/declarations/rule.rb +38 -43
- data/lib/expressir/model/declarations/schema.rb +162 -64
- data/lib/expressir/model/declarations/schema_version.rb +8 -11
- data/lib/expressir/model/declarations/schema_version_item.rb +8 -11
- data/lib/expressir/model/declarations/subtype_constraint.rb +14 -22
- data/lib/expressir/model/declarations/type.rb +18 -18
- data/lib/expressir/model/declarations/unique_rule.rb +8 -13
- data/lib/expressir/model/declarations/variable.rb +10 -16
- data/lib/expressir/model/declarations/where_rule.rb +8 -13
- data/lib/expressir/model/declarations.rb +31 -0
- data/lib/expressir/model/dependency_resolver.rb +268 -0
- data/lib/expressir/model/exp_file.rb +42 -0
- data/lib/expressir/model/expressions/aggregate_initializer.rb +8 -9
- data/lib/expressir/model/expressions/aggregate_initializer_item.rb +10 -12
- data/lib/expressir/model/expressions/binary_expression.rb +42 -36
- data/lib/expressir/model/expressions/entity_constructor.rb +10 -12
- data/lib/expressir/model/expressions/function_call.rb +10 -12
- data/lib/expressir/model/expressions/interval.rb +18 -23
- data/lib/expressir/model/expressions/query_expression.rb +11 -15
- data/lib/expressir/model/expressions/unary_expression.rb +13 -15
- data/lib/expressir/model/expressions.rb +18 -0
- data/lib/expressir/model/identifier.rb +18 -26
- data/lib/expressir/model/indexes/entity_index.rb +103 -0
- data/lib/expressir/model/indexes/item_graph.rb +185 -0
- data/lib/expressir/model/indexes/reference_index.rb +148 -0
- data/lib/expressir/model/indexes/type_index.rb +149 -0
- data/lib/expressir/model/indexes.rb +12 -0
- data/lib/expressir/model/interface_validator.rb +384 -0
- data/lib/expressir/model/literals/binary.rb +7 -9
- data/lib/expressir/model/literals/integer.rb +7 -9
- data/lib/expressir/model/literals/logical.rb +10 -12
- data/lib/expressir/model/literals/real.rb +7 -9
- data/lib/expressir/model/literals/string.rb +10 -12
- data/lib/expressir/model/literals.rb +13 -0
- data/lib/expressir/model/model_element.rb +286 -117
- data/lib/expressir/model/references/attribute_reference.rb +9 -12
- data/lib/expressir/model/references/group_reference.rb +9 -12
- data/lib/expressir/model/references/index_reference.rb +11 -15
- data/lib/expressir/model/references/simple_reference.rb +11 -14
- data/lib/expressir/model/references.rb +12 -0
- data/lib/expressir/model/remark_format.rb +17 -0
- data/lib/expressir/model/remark_info.rb +92 -0
- data/lib/expressir/model/remark_placement.rb +42 -0
- data/lib/expressir/model/repository.rb +472 -12
- data/lib/expressir/model/repository_validator.rb +293 -0
- data/lib/expressir/model/search_engine.rb +551 -0
- data/lib/expressir/model/statements/alias.rb +12 -16
- data/lib/expressir/model/statements/assignment.rb +12 -11
- data/lib/expressir/model/statements/case.rb +31 -14
- data/lib/expressir/model/statements/case_action.rb +9 -11
- data/lib/expressir/model/statements/compound.rb +10 -8
- data/lib/expressir/model/statements/escape.rb +10 -2
- data/lib/expressir/model/statements/if.rb +15 -14
- data/lib/expressir/model/statements/null.rb +10 -2
- data/lib/expressir/model/statements/procedure_call.rb +11 -11
- data/lib/expressir/model/statements/repeat.rb +21 -28
- data/lib/expressir/model/statements/return.rb +9 -8
- data/lib/expressir/model/statements/skip.rb +10 -2
- data/lib/expressir/model/statements.rb +20 -0
- data/lib/expressir/model/supertype_expressions/binary_supertype_expression.rb +13 -17
- data/lib/expressir/model/supertype_expressions/oneof_supertype_expression.rb +7 -9
- data/lib/expressir/model/supertype_expressions.rb +12 -0
- data/lib/expressir/model.rb +38 -78
- data/lib/expressir/package/builder.rb +231 -0
- data/lib/expressir/package/metadata.rb +79 -0
- data/lib/expressir/package/reader.rb +149 -0
- data/lib/expressir/package.rb +8 -0
- data/lib/expressir/schema_manifest.rb +159 -0
- data/lib/expressir/schema_manifest_entry.rb +15 -0
- data/lib/expressir/version.rb +6 -1
- data/lib/expressir.rb +79 -9
- data/lib/tasks/verify_remarks.rake +16 -0
- data/rakelib/native.rake +24 -0
- data/rakelib/oracle.rake +52 -0
- data/rakelib/verify_remarks.rake +16 -0
- metadata +431 -129
- data/.cross_rubies +0 -20
- data/.gitmodules +0 -6
- data/.yardopts +0 -11
- data/docs/development.md +0 -90
- data/exe/format +0 -18
- data/exe/generate-parser +0 -51
- data/lib/expressir/cli/ui.rb +0 -36
- data/lib/expressir/express/2.7/express_parser.so +0 -0
- data/lib/expressir/express/3.0/express_parser.so +0 -0
- data/lib/expressir/express/3.1/express_parser.so +0 -0
- data/lib/expressir/express/3.2/express_parser.so +0 -0
- data/lib/expressir/express/visitor.rb +0 -2588
- data/lib/expressir/model/data_type.rb +0 -9
- data/lib/expressir/model/declaration.rb +0 -9
- data/lib/expressir/model/expression.rb +0 -9
- data/lib/expressir/model/literal.rb +0 -9
- data/lib/expressir/model/reference.rb +0 -9
- data/lib/expressir/model/statement.rb +0 -9
- data/lib/expressir/model/supertype_expression.rb +0 -9
- data/rakelib/antlr4-native.rake +0 -161
- data/rakelib/cross-ruby.rake +0 -368
- data/spec/acceptance/version_spec.rb +0 -27
- data/spec/expressir/express/cache_spec.rb +0 -89
- data/spec/expressir/express/formatter_spec.rb +0 -173
- data/spec/expressir/express/parser_spec.rb +0 -141
- data/spec/expressir/model/model_element_spec.rb +0 -318
- data/spec/spec_helper.rb +0 -24
- data/spec/support/console_helper.rb +0 -29
- data/spec/syntax/multiple.exp +0 -23
- data/spec/syntax/multiple.yaml +0 -198
- data/spec/syntax/multiple_formatted.exp +0 -71
- data/spec/syntax/multiple_hyperlink_formatted.exp +0 -71
- data/spec/syntax/multiple_schema_head_hyperlink_formatted.exp +0 -13
- data/spec/syntax/remark.exp +0 -193
- data/spec/syntax/remark.yaml +0 -471
- data/spec/syntax/remark_formatted.exp +0 -228
- data/spec/syntax/single.exp +0 -4
- data/spec/syntax/single.yaml +0 -18
- data/spec/syntax/single_formatted.exp +0 -10
- data/spec/syntax/single_formatted.yaml +0 -36
- data/spec/syntax/syntax.exp +0 -333
- data/spec/syntax/syntax.yaml +0 -3509
- data/spec/syntax/syntax_formatted.exp +0 -902
- data/spec/syntax/syntax_hyperlink_formatted.exp +0 -902
- data/spec/syntax/syntax_schema_head_formatted.exp +0 -18
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Expressir
|
|
4
|
+
# Base error class with details support
|
|
5
|
+
class Error < StandardError
|
|
6
|
+
attr_reader :details
|
|
7
|
+
|
|
8
|
+
def initialize(message = nil, details: nil)
|
|
9
|
+
@details = details
|
|
10
|
+
super(message)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# File/Resource Errors
|
|
15
|
+
class FileNotFoundError < Error
|
|
16
|
+
attr_reader :file_path, :file_type
|
|
17
|
+
|
|
18
|
+
def initialize(file_path, file_type: nil)
|
|
19
|
+
@file_path = file_path
|
|
20
|
+
@file_type = file_type
|
|
21
|
+
super("#{file_type || 'File'} not found: #{file_path}")
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class ManifestNotFoundError < FileNotFoundError
|
|
26
|
+
def initialize(file_path)
|
|
27
|
+
super(file_path, file_type: "Manifest file")
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class PackageNotFoundError < FileNotFoundError
|
|
32
|
+
def initialize(file_path)
|
|
33
|
+
super(file_path, file_type: "Package file")
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class SchemaNotFoundError < FileNotFoundError
|
|
38
|
+
def initialize(file_path)
|
|
39
|
+
super(file_path, file_type: "Schema file")
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Usage/Argument Errors
|
|
44
|
+
class UsageError < Error
|
|
45
|
+
attr_reader :usage_hint
|
|
46
|
+
|
|
47
|
+
def initialize(message, usage_hint: nil)
|
|
48
|
+
@usage_hint = usage_hint
|
|
49
|
+
super(message)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class MissingRequiredArgumentError < UsageError; end
|
|
54
|
+
|
|
55
|
+
class InvalidOptionError < UsageError
|
|
56
|
+
attr_reader :option_name, :valid_options
|
|
57
|
+
|
|
58
|
+
def initialize(option_name, value, valid_options: nil)
|
|
59
|
+
@option_name = option_name
|
|
60
|
+
@valid_options = valid_options
|
|
61
|
+
msg = "Invalid value '#{value}' for #{option_name}"
|
|
62
|
+
msg += ". Valid options: #{valid_options.join(', ')}" if valid_options
|
|
63
|
+
super(msg)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Validation Errors
|
|
68
|
+
class ValidationError < Error
|
|
69
|
+
attr_reader :errors
|
|
70
|
+
|
|
71
|
+
def initialize(message, errors: [])
|
|
72
|
+
@errors = errors
|
|
73
|
+
super(message)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
class ManifestValidationError < ValidationError; end
|
|
78
|
+
class SchemaValidationError < ValidationError; end
|
|
79
|
+
|
|
80
|
+
class ReferentialIntegrityError < ValidationError
|
|
81
|
+
attr_reader :unresolved_references
|
|
82
|
+
|
|
83
|
+
def initialize(unresolved_references,
|
|
84
|
+
message: "Referential integrity check failed")
|
|
85
|
+
@unresolved_references = unresolved_references
|
|
86
|
+
super(message)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
class NoValidSchemaPathsError < ValidationError
|
|
91
|
+
def initialize(message = "No valid schema paths found")
|
|
92
|
+
super
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Command Errors (for rescue blocks)
|
|
97
|
+
class CommandError < Error
|
|
98
|
+
attr_reader :command_name
|
|
99
|
+
|
|
100
|
+
def initialize(message, command_name: nil)
|
|
101
|
+
@command_name = command_name
|
|
102
|
+
super(message)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
class PackageBuildError < CommandError; end
|
|
107
|
+
class PackageReadError < CommandError; end
|
|
108
|
+
class PackageExtractError < CommandError; end
|
|
109
|
+
class PackageValidationError < CommandError; end
|
|
110
|
+
class PackageListError < CommandError; end
|
|
111
|
+
class PackageSearchError < CommandError; end
|
|
112
|
+
class PackageTreeError < CommandError; end
|
|
113
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Expressir
|
|
4
|
+
module Express
|
|
5
|
+
# HyperlinkFormatter variant emitting AsciiDoc xref macros instead
|
|
6
|
+
# of the legacy stepmod +{{{<<express:...>>}}}+ markup: a reference
|
|
7
|
+
# to schema.item renders as +<<schema.item,item>>+, the anchor
|
|
8
|
+
# namespace schema document pages emit (expressir #255 / iso-10303
|
|
9
|
+
# #41). With +subs="+macros"+ source blocks the links go live.
|
|
10
|
+
module AdocHyperlinkFormatter
|
|
11
|
+
# @!visibility private
|
|
12
|
+
def self.included(mod)
|
|
13
|
+
unless mod.superclass <= Expressir::Express::Formatter
|
|
14
|
+
raise Error::FormatterMethodMissingError.new("AdocHyperlinkFormatter",
|
|
15
|
+
"format_references_simple_reference")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def format_references_simple_reference(node)
|
|
20
|
+
return node.id unless node.base_path
|
|
21
|
+
|
|
22
|
+
parts = node.base_path.split(".")
|
|
23
|
+
return node.id if parts.size < 2
|
|
24
|
+
|
|
25
|
+
anchor = parts[-2, 2].join(".")
|
|
26
|
+
"<<#{anchor},#{node.id}>>"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Expressir
|
|
4
|
+
module Express
|
|
5
|
+
# Pre-built Formatter subclass rendering the FULL schema with
|
|
6
|
+
# cross-references as AsciiDoc xref macros — the document-page
|
|
7
|
+
# counterpart of SourceFormatter (Schema#formatted_hyperlinked_adoc).
|
|
8
|
+
class AdocSourceFormatter < Formatter
|
|
9
|
+
include AdocHyperlinkFormatter
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Expressir
|
|
4
|
+
module Express
|
|
5
|
+
# Converts native-AST CamelCase keys to the snake_case keys the
|
|
6
|
+
# builders consume.
|
|
7
|
+
#
|
|
8
|
+
# build() descends into child nodes whose subtrees the parent already
|
|
9
|
+
# converted, so unchanged containers are marked with an invisible
|
|
10
|
+
# instance variable and skipped on re-visits — without it, every
|
|
11
|
+
# subtree is re-scanned once per ancestor level (~60 convert calls per
|
|
12
|
+
# model node on real schemas). The marker is invisible to equality,
|
|
13
|
+
# hashing, and inspection.
|
|
14
|
+
class AstKeyConverter
|
|
15
|
+
SNAKED_MARKER = :@_expressir_keys_snaked
|
|
16
|
+
UPPERCASE_PATTERN = /[A-Z]/
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
# Thread-local snake_case conversion cache. Thread-local avoids the
|
|
20
|
+
# mutable-constant anti-pattern while remaining thread-safe. The
|
|
21
|
+
# cache is bounded by the number of unique AST node-type names.
|
|
22
|
+
def snake_case(name)
|
|
23
|
+
cache[name] ||= begin
|
|
24
|
+
str = name.to_s
|
|
25
|
+
if /^[a-z_]+$/.match?(str)
|
|
26
|
+
str.to_sym
|
|
27
|
+
else
|
|
28
|
+
str
|
|
29
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
30
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
31
|
+
.downcase
|
|
32
|
+
.to_sym
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Returns the original object when no conversion is needed; the
|
|
38
|
+
# common no-conversion case allocates nothing and the conversion
|
|
39
|
+
# case walks the keys once.
|
|
40
|
+
def convert(obj)
|
|
41
|
+
case obj
|
|
42
|
+
when Hash
|
|
43
|
+
return obj if obj.empty?
|
|
44
|
+
return obj if obj.instance_variable_defined?(SNAKED_MARKER)
|
|
45
|
+
|
|
46
|
+
keys = obj.keys
|
|
47
|
+
converted_values = nil
|
|
48
|
+
new_keys = nil
|
|
49
|
+
|
|
50
|
+
keys.each_with_index do |k, i|
|
|
51
|
+
val = obj[k]
|
|
52
|
+
case val
|
|
53
|
+
when Hash, Array
|
|
54
|
+
unless val.empty?
|
|
55
|
+
converted_val = convert(val)
|
|
56
|
+
(converted_values ||= {})[k] = converted_val unless converted_val.equal?(val)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
if k.match?(UPPERCASE_PATTERN)
|
|
61
|
+
(new_keys ||= keys.dup)[i] = snake_case(k)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
return mark_snaked(obj) unless new_keys || converted_values
|
|
66
|
+
|
|
67
|
+
result = {}
|
|
68
|
+
keys.each_with_index do |k, i|
|
|
69
|
+
key = new_keys&.[](i) || k
|
|
70
|
+
result[key] = converted_values&.key?(k) ? converted_values[k] : obj[k]
|
|
71
|
+
end
|
|
72
|
+
mark_snaked(result)
|
|
73
|
+
when Array
|
|
74
|
+
return obj if obj.empty?
|
|
75
|
+
return obj if obj.instance_variable_defined?(SNAKED_MARKER)
|
|
76
|
+
|
|
77
|
+
needs_conversion = false
|
|
78
|
+
result = []
|
|
79
|
+
|
|
80
|
+
obj.each do |item|
|
|
81
|
+
case item
|
|
82
|
+
when Hash, Array
|
|
83
|
+
next if item.empty?
|
|
84
|
+
|
|
85
|
+
converted = convert(item)
|
|
86
|
+
result << converted
|
|
87
|
+
needs_conversion = true unless converted.equal?(item)
|
|
88
|
+
else
|
|
89
|
+
result << item
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
needs_conversion ? mark_snaked(result) : mark_snaked(obj)
|
|
94
|
+
else
|
|
95
|
+
obj
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
def cache
|
|
102
|
+
Thread.current[:expressir_snake_case_cache] ||= {}
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def mark_snaked(obj)
|
|
106
|
+
obj.instance_variable_set(SNAKED_MARKER, true)
|
|
107
|
+
obj
|
|
108
|
+
rescue FrozenError
|
|
109
|
+
obj
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Expressir
|
|
4
|
+
module Express
|
|
5
|
+
# Builder registry for AST node type handlers.
|
|
6
|
+
# Each builder is a callable object that transforms AST data into Model objects.
|
|
7
|
+
# This is the ONLY way to build models from AST - no Transformer fallback.
|
|
8
|
+
module Builder
|
|
9
|
+
class << self
|
|
10
|
+
# Thread-local key under which the current BuilderContext is stored
|
|
11
|
+
# for the duration of a build_with_remarks call. Recursive build
|
|
12
|
+
# calls read source/include_source from here instead of from
|
|
13
|
+
# class-level mutable state.
|
|
14
|
+
CONTEXT_KEY = :expressir_builder_context
|
|
15
|
+
|
|
16
|
+
# Returns the BuilderContext for the current thread, or nil if no
|
|
17
|
+
# build is in progress.
|
|
18
|
+
def current_context
|
|
19
|
+
Thread.current[CONTEXT_KEY]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Convenience accessors — read from the current context.
|
|
23
|
+
def source
|
|
24
|
+
current_context&.source
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def include_source
|
|
28
|
+
current_context&.include_source
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Register a builder for a node type.
|
|
32
|
+
# @param node_type [Symbol] The AST node type
|
|
33
|
+
# @param builder [#call] Optional callable that takes (ast_data)
|
|
34
|
+
# @yield Block that takes (ast_data) if builder not provided
|
|
35
|
+
def register(node_type, builder = nil, &block)
|
|
36
|
+
@register ||= {}
|
|
37
|
+
@register[node_type] = builder || block
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Build a Model object from AST data.
|
|
41
|
+
# @param ast [Hash] The AST with node type as key
|
|
42
|
+
# @return [Model::ModelElement] The built model object
|
|
43
|
+
def build(ast)
|
|
44
|
+
return nil unless ast
|
|
45
|
+
|
|
46
|
+
# Optimized: Hash is 90%+ of cases, check it first
|
|
47
|
+
case ast
|
|
48
|
+
when Hash
|
|
49
|
+
node_type = ast.keys.first
|
|
50
|
+
node_data = ast[node_type]
|
|
51
|
+
|
|
52
|
+
handler_key = AstKeyConverter.snake_case(node_type)
|
|
53
|
+
snake_data = AstKeyConverter.convert(node_data)
|
|
54
|
+
|
|
55
|
+
builder = @register[handler_key]
|
|
56
|
+
if builder
|
|
57
|
+
result = builder.call(snake_data)
|
|
58
|
+
|
|
59
|
+
# Fast path: single-key hash or non-nil result
|
|
60
|
+
if !result.nil? || ast.keys.length <= 1
|
|
61
|
+
attach_source_info(result, node_data)
|
|
62
|
+
return result
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Slow path: first-key builder returned nil in a multi-key
|
|
66
|
+
# hash. Try remaining keys for actual content. This handles
|
|
67
|
+
# grammar patterns like `element >> (op_comma >> element).repeat`
|
|
68
|
+
# which produce {:op_comma => ..., :element => {...}} where
|
|
69
|
+
# the first key is an operator separator.
|
|
70
|
+
# Previously gated by a hand-maintained OPERATOR_TOKENS set;
|
|
71
|
+
# now tries all remaining keys unconditionally (TODO.bugs/21).
|
|
72
|
+
ast.each_key do |key|
|
|
73
|
+
next if key == node_type
|
|
74
|
+
|
|
75
|
+
h_key = AstKeyConverter.snake_case(key)
|
|
76
|
+
h_builder = @register[h_key]
|
|
77
|
+
next unless h_builder
|
|
78
|
+
|
|
79
|
+
n_data = ast[key]
|
|
80
|
+
s_data = AstKeyConverter.convert(n_data)
|
|
81
|
+
result = h_builder.call(s_data)
|
|
82
|
+
|
|
83
|
+
unless result.nil?
|
|
84
|
+
attach_source_info(result, n_data)
|
|
85
|
+
return result
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
else
|
|
89
|
+
raise Error::UnknownNodeTypeError, node_type
|
|
90
|
+
end
|
|
91
|
+
nil
|
|
92
|
+
when Array
|
|
93
|
+
ast.map do |item|
|
|
94
|
+
build(item)
|
|
95
|
+
end
|
|
96
|
+
when Parsanol::Slice
|
|
97
|
+
ast.to_s
|
|
98
|
+
else
|
|
99
|
+
ast
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Build with remark attachment.
|
|
104
|
+
#
|
|
105
|
+
# Sets up a BuilderContext as a thread-local for the duration of the
|
|
106
|
+
# build so recursive build calls can read source/include_source via
|
|
107
|
+
# `Builder.source` / `Builder.include_source`. The previous context
|
|
108
|
+
# (if any) is restored on exit so nested builds are reentrant.
|
|
109
|
+
def build_with_remarks(ast, source: nil, include_source: nil)
|
|
110
|
+
# Trigger BuilderRegistry autoload so all AST node type handlers
|
|
111
|
+
# are registered before build() runs. The reference to
|
|
112
|
+
# BuilderRegistry resolves the autoload defined in express.rb.
|
|
113
|
+
BuilderRegistry
|
|
114
|
+
|
|
115
|
+
previous = Thread.current[CONTEXT_KEY]
|
|
116
|
+
Thread.current[CONTEXT_KEY] = BuilderContext.new(
|
|
117
|
+
source: source,
|
|
118
|
+
include_source: include_source,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
result = build(ast)
|
|
122
|
+
|
|
123
|
+
# Only attach remarks if include_source is explicitly true
|
|
124
|
+
# (nil means use default behavior - attach remarks)
|
|
125
|
+
if source && result && include_source != false
|
|
126
|
+
attacher = RemarkAttacher.new(source)
|
|
127
|
+
attacher.attach(result)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
result
|
|
131
|
+
ensure
|
|
132
|
+
Thread.current[CONTEXT_KEY] = previous
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Check if a builder is registered for a node type.
|
|
136
|
+
def registered?(node_type)
|
|
137
|
+
@register&.key?(node_type)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Get all registered node types.
|
|
141
|
+
def registered_types
|
|
142
|
+
@register&.keys || []
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Build optional (returns nil if ast is nil)
|
|
146
|
+
def build_optional(ast)
|
|
147
|
+
return nil unless ast
|
|
148
|
+
|
|
149
|
+
build(ast)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Normalize a value to an Array for iteration.
|
|
153
|
+
# Handles: nil → [], Parsanol::Slice → [], Array → Array, other → [other]
|
|
154
|
+
def ensure_array(value)
|
|
155
|
+
return [] if value.nil?
|
|
156
|
+
return [] if value.is_a?(Parsanol::Slice)
|
|
157
|
+
|
|
158
|
+
value.is_a?(Array) ? value : [value]
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Build children (array of AST nodes)
|
|
162
|
+
# Optimized to avoid intermediate array allocations
|
|
163
|
+
def build_children(ast_array)
|
|
164
|
+
return [] if ast_array.nil?
|
|
165
|
+
|
|
166
|
+
# Handle Parsanol::Slice (empty Slices from optional rules)
|
|
167
|
+
# Convert to empty Array
|
|
168
|
+
if ast_array.is_a?(Parsanol::Slice)
|
|
169
|
+
return []
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Handle single element (common case)
|
|
173
|
+
unless ast_array.is_a?(Array)
|
|
174
|
+
return [build(ast_array)].compact
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Build result in single pass, avoiding flatten/compact/map chain
|
|
178
|
+
result = []
|
|
179
|
+
ast_array.each do |item|
|
|
180
|
+
next if item.nil?
|
|
181
|
+
|
|
182
|
+
# Empty Slices from optional rules should be treated as empty arrays
|
|
183
|
+
if item.is_a?(Parsanol::Slice)
|
|
184
|
+
next
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
case item
|
|
188
|
+
when Array
|
|
189
|
+
item.each do |sub|
|
|
190
|
+
result << build(sub) unless sub.nil?
|
|
191
|
+
end
|
|
192
|
+
else
|
|
193
|
+
built = build(item)
|
|
194
|
+
result << built if built
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
result
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Fast build methods - call registered builder directly without hash wrapping
|
|
201
|
+
# These are optimized for hot paths in expression building
|
|
202
|
+
# NOTE: These assume data is already snake_case (no key conversion needed)
|
|
203
|
+
|
|
204
|
+
# Call a registered builder directly with data (avoids hash wrapper allocation)
|
|
205
|
+
# @param node_type [Symbol] The node type key
|
|
206
|
+
# @param data The data to pass to the builder (already snake_case)
|
|
207
|
+
def build_node(node_type, data)
|
|
208
|
+
builder = @register&.[](node_type)
|
|
209
|
+
raise Error::UnknownNodeTypeError, node_type unless builder
|
|
210
|
+
|
|
211
|
+
builder.call(data)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Keys containing uppercase need snake-casing; testing the key
|
|
215
|
+
# directly avoids allocating `to_s` strings per key per pass.
|
|
216
|
+
# Key conversion lives in AstKeyConverter (MECE: converting AST
|
|
217
|
+
# keys is not building models).
|
|
218
|
+
def extract_source_info(data)
|
|
219
|
+
return nil unless data
|
|
220
|
+
|
|
221
|
+
src = source
|
|
222
|
+
return nil unless src
|
|
223
|
+
|
|
224
|
+
slice = find_slice(data)
|
|
225
|
+
return nil unless slice
|
|
226
|
+
|
|
227
|
+
{
|
|
228
|
+
text: src[slice.offset...(slice.offset + slice.length)]&.strip,
|
|
229
|
+
offset: slice.offset,
|
|
230
|
+
}
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def attach_source_info(result, data)
|
|
234
|
+
return unless source && result.is_a?(Expressir::Model::ModelElement)
|
|
235
|
+
|
|
236
|
+
source_info = extract_source_info(data)
|
|
237
|
+
return unless source_info
|
|
238
|
+
|
|
239
|
+
result.source_offset = source_info[:offset]
|
|
240
|
+
result.source = source_info[:text] if include_source
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def find_slice(data, depth = 0)
|
|
244
|
+
return nil if depth > 10
|
|
245
|
+
|
|
246
|
+
case data
|
|
247
|
+
when Parsanol::Slice
|
|
248
|
+
data
|
|
249
|
+
when Hash
|
|
250
|
+
# Skip 'spaces' key which contains whitespace/comments before content
|
|
251
|
+
# Look for 'str' key first as it usually contains the actual content
|
|
252
|
+
if data.key?(:str) && data[:str].is_a?(Parsanol::Slice)
|
|
253
|
+
return data[:str]
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# Then look in other keys, skipping 'spaces'
|
|
257
|
+
data.each do |key, value|
|
|
258
|
+
next if key == :spaces
|
|
259
|
+
|
|
260
|
+
return value if value.is_a?(Parsanol::Slice)
|
|
261
|
+
|
|
262
|
+
result = find_slice(value, depth + 1)
|
|
263
|
+
return result if result
|
|
264
|
+
end
|
|
265
|
+
nil
|
|
266
|
+
when Array
|
|
267
|
+
data.each do |item|
|
|
268
|
+
result = find_slice(item, depth + 1)
|
|
269
|
+
return result if result
|
|
270
|
+
end
|
|
271
|
+
nil
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Expressir
|
|
4
|
+
module Express
|
|
5
|
+
# Value object carrying the per-build context that Builder needs to
|
|
6
|
+
# attach source info to model elements.
|
|
7
|
+
#
|
|
8
|
+
# Stored as a thread-local by Builder.build_with_remarks so that recursive
|
|
9
|
+
# build calls can read `Builder.source` / `Builder.include_source` without
|
|
10
|
+
# the module mutating class-level state. Thread-local means concurrent
|
|
11
|
+
# builds in different threads don't corrupt each other; the save/restore
|
|
12
|
+
# pattern in build_with_remarks means nested builds are reentrant.
|
|
13
|
+
class BuilderContext
|
|
14
|
+
attr_reader :source, :include_source
|
|
15
|
+
|
|
16
|
+
def initialize(source:, include_source:)
|
|
17
|
+
@source = source
|
|
18
|
+
@include_source = include_source
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|