ibex 0.2.0 → 0.3.0
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/README.md +95 -272
- data/docs/architecture.md +187 -35
- data/docs/bison-import.md +103 -0
- data/docs/comparison-policy.md +127 -0
- data/docs/configuration-model.md +59 -0
- data/docs/configuration-report.md +28 -0
- data/docs/conflict-explanation-reviews/v1/records/README.md +28 -0
- data/docs/conflict-explanation-study.md +62 -0
- data/docs/construction-profiling.md +157 -0
- data/docs/cst-migration.md +3 -4
- data/docs/cst.md +24 -0
- data/docs/decisions/0000-template.md +24 -0
- data/docs/decisions/0001-separate-ir-pipeline.md +34 -0
- data/docs/decisions/0002-opaque-user-code-boundary.md +32 -0
- data/docs/decisions/0003-self-hosted-grammar-frontend.md +32 -0
- data/docs/decisions/0004-shared-semantic-and-lossless-source-model.md +33 -0
- data/docs/decisions/0005-contained-grammar-composition.md +34 -0
- data/docs/decisions/0006-bounded-structural-grammar-lowering.md +32 -0
- data/docs/decisions/0007-shared-parser-construction-pipeline.md +33 -0
- data/docs/decisions/0008-versioned-runtime-package-boundary.md +36 -0
- data/docs/decisions/0009-isolated-parser-sessions.md +34 -0
- data/docs/decisions/0010-committed-runtime-observation.md +34 -0
- data/docs/decisions/0011-versioned-semantic-action-boundary.md +37 -0
- data/docs/decisions/0012-bounded-nonexecuting-analysis.md +37 -0
- data/docs/decisions/0013-transactional-generation-publication.md +37 -0
- data/docs/decisions/0014-versioned-generated-lexer.md +35 -0
- data/docs/decisions/0015-worker-isolated-browser-analysis.md +32 -0
- data/docs/decisions/0016-red-green-concrete-syntax.md +34 -0
- data/docs/decisions/0017-persistent-syntax-artifacts.md +35 -0
- data/docs/decisions/0018-conservative-incremental-syntax-reuse.md +38 -0
- data/docs/decisions/0019-runtime-syntax-session-boundary.md +51 -0
- data/docs/decisions/0020-grammar-ir-parser-contract.md +65 -0
- data/docs/decisions/0021-data-only-parser-table-sidecar.md +50 -0
- data/docs/decisions/0022-manifest-bound-verification-report.md +77 -0
- data/docs/decisions/0023-syntax-only-repair-results.md +48 -0
- data/docs/decisions/0024-direct-ielr-construction.md +42 -0
- data/docs/decisions/README.md +74 -0
- data/docs/declarative-configuration.md +262 -0
- data/docs/development.md +179 -2
- data/docs/direct-ielr-decision.md +120 -0
- data/docs/direct-multi-entry-decision.md +82 -0
- data/docs/editor-setup.md +2 -1
- data/docs/error-ux-review-rubric-v1.md +117 -0
- data/docs/error-ux-reviews/v1/records/README.md +22 -0
- data/docs/error-ux-round2-review-status-v1.json +27 -0
- data/docs/error-ux-round2-reviews/v1/records/README.md +30 -0
- data/docs/error-ux-round2-v1.json +1581 -0
- data/docs/error-ux-round2.md +111 -0
- data/docs/error-ux.md +54 -0
- data/docs/getting-started.md +80 -0
- data/docs/grammar-reference.md +184 -13
- data/docs/ielr-design.md +43 -0
- data/docs/ielr.md +92 -0
- data/docs/ja/bison-import.md +51 -0
- data/docs/ja/stable-api.md +53 -0
- data/docs/lexer-construction-profile.md +109 -0
- data/docs/lexer-migration.md +5 -0
- data/docs/maturity.md +128 -0
- data/docs/project-site-strategy.md +54 -0
- data/docs/racc-migration-evidence.md +45 -0
- data/docs/racc-migration.md +11 -0
- data/docs/release-readiness.md +126 -68
- data/docs/repair-semantics.md +123 -0
- data/docs/runtime-abi-evolution.md +307 -0
- data/docs/stability.md +144 -34
- data/docs/status.md +43 -0
- data/docs/syntax-sessions.md +183 -0
- data/docs/table-artifact.md +125 -0
- data/docs/test-interactions.md +219 -0
- data/docs/verification-report.md +137 -0
- data/docs/verifier-trust-boundary.md +199 -0
- data/docs/workloads.md +132 -0
- data/lib/ibex/analysis/digraph.rb +128 -0
- data/lib/ibex/analysis.rb +1 -0
- data/lib/ibex/bison_import/importer.rb +516 -0
- data/lib/ibex/bison_import/tokenizer.rb +260 -0
- data/lib/ibex/bison_import.rb +200 -0
- data/lib/ibex/bounded_subprocess.rb +171 -0
- data/lib/ibex/cli/ambiguity.rb +14 -5
- data/lib/ibex/cli/analysis.rb +134 -0
- data/lib/ibex/cli/bison_import.rb +121 -0
- data/lib/ibex/cli/config.rb +128 -0
- data/lib/ibex/cli/diagnostics.rb +31 -11
- data/lib/ibex/cli/documentation.rb +11 -8
- data/lib/ibex/cli/equiv.rb +169 -0
- data/lib/ibex/cli/error_messages.rb +11 -4
- data/lib/ibex/cli/explain.rb +14 -5
- data/lib/ibex/cli/fix.rb +203 -0
- data/lib/ibex/cli/formatting.rb +11 -10
- data/lib/ibex/cli/fuzz.rb +200 -0
- data/lib/ibex/cli/fuzz_regressions.rb +145 -0
- data/lib/ibex/cli/generation_artifacts.rb +53 -2
- data/lib/ibex/cli/generation_error_messages.rb +1 -1
- data/lib/ibex/cli/grammar_tests.rb +32 -14
- data/lib/ibex/cli/ir_tools.rb +5 -61
- data/lib/ibex/cli/outputs.rb +60 -33
- data/lib/ibex/cli/reduce.rb +202 -0
- data/lib/ibex/cli/reduce_reporting.rb +71 -0
- data/lib/ibex/cli/samples.rb +49 -23
- data/lib/ibex/cli/verify.rb +116 -0
- data/lib/ibex/cli/watch.rb +6 -5
- data/lib/ibex/cli.rb +357 -56
- data/lib/ibex/codegen/action_locations.rb +1 -1
- data/lib/ibex/codegen/action_method_source.rb +5 -6
- data/lib/ibex/codegen/action_source.rb +3 -2
- data/lib/ibex/codegen/ambiguity.rb +5 -4
- data/lib/ibex/codegen/explain.rb +123 -55
- data/lib/ibex/codegen/generated_action_abi.rb +10 -5
- data/lib/ibex/codegen/rbs.rb +15 -7
- data/lib/ibex/codegen/report.rb +25 -13
- data/lib/ibex/codegen/ruby.rb +28 -64
- data/lib/ibex/codegen/ruby_actions.rb +9 -6
- data/lib/ibex/codegen/ruby_syntax.rb +15 -9
- data/lib/ibex/configuration/analysis_grammar.rb +35 -0
- data/lib/ibex/configuration/explanation.rb +421 -0
- data/lib/ibex/configuration/inspector.rb +232 -0
- data/lib/ibex/configuration.rb +580 -0
- data/lib/ibex/coverage/collector.rb +21 -11
- data/lib/ibex/coverage/event_stream.rb +13 -7
- data/lib/ibex/coverage/report.rb +26 -18
- data/lib/ibex/coverage/runtime_event_validator.rb +30 -21
- data/lib/ibex/delta_reducer.rb +99 -0
- data/lib/ibex/diff.rb +140 -0
- data/lib/ibex/equiv/machine.rb +135 -0
- data/lib/ibex/equiv.rb +373 -0
- data/lib/ibex/fix.rb +557 -0
- data/lib/ibex/frontend/ast.rb +22 -2
- data/lib/ibex/frontend/bootstrap_parser.rb +6 -13
- data/lib/ibex/frontend/diagnostic.rb +1 -1
- data/lib/ibex/frontend/formatter.rb +72 -26
- data/lib/ibex/frontend/generated_parser.rb +147 -117
- data/lib/ibex/frontend/generated_parser_base.rb +7 -3
- data/lib/ibex/frontend/generated_parser_includes.rb +1 -11
- data/lib/ibex/frontend/generation.rb +1 -1
- data/lib/ibex/frontend/parser/declarations.rb +17 -2
- data/lib/ibex/frontend/parser_configuration_support.rb +56 -0
- data/lib/ibex/frontend/regenerator.rb +1 -0
- data/lib/ibex/frontend/resolution.rb +2 -1
- data/lib/ibex/frontend/resolver.rb +1 -1
- data/lib/ibex/frontend/rule_documentation.rb +2 -1
- data/lib/ibex/frontend/source_cursor.rb +2 -2
- data/lib/ibex/frontend/source_span.rb +9 -1
- data/lib/ibex/frontend/token_adapter/declaration_state.rb +38 -6
- data/lib/ibex/frontend/token_adapter.rb +10 -0
- data/lib/ibex/frontend.rb +1 -0
- data/lib/ibex/fuzz.rb +219 -0
- data/lib/ibex/generation_input.rb +1 -1
- data/lib/ibex/generation_manifest.rb +36 -25
- data/lib/ibex/generation_transaction.rb +1 -1
- data/lib/ibex/generation_transaction_recovery.rb +4 -4
- data/lib/ibex/generation_transaction_validation.rb +2 -2
- data/lib/ibex/grammar_tests.rb +1 -1
- data/lib/ibex/ir/automaton_ir.rb +61 -19
- data/lib/ibex/ir/grammar_ir.rb +76 -45
- data/lib/ibex/ir/lexer_ir.rb +5 -5
- data/lib/ibex/ir/parser_contract.rb +135 -0
- data/lib/ibex/ir/serialize.rb +203 -76
- data/lib/ibex/ir/validator/automaton.rb +64 -34
- data/lib/ibex/ir/validator/base.rb +51 -33
- data/lib/ibex/ir/validator/grammar.rb +113 -83
- data/lib/ibex/ir/validator/lexer.rb +2 -2
- data/lib/ibex/ir/validator.rb +2 -1
- data/lib/ibex/ir.rb +16 -3
- data/lib/ibex/lalr/build_metrics.rb +50 -2
- data/lib/ibex/lalr/builder.rb +191 -56
- data/lib/ibex/lalr/conflict_search.rb +15 -4
- data/lib/ibex/lalr/counterexample.rb +19 -14
- data/lib/ibex/lalr/direct_lookaheads.rb +110 -57
- data/lib/ibex/lalr/goto_follows.rb +229 -0
- data/lib/ibex/lalr/ielr/annotator.rb +214 -0
- data/lib/ibex/lalr/ielr/bits.rb +28 -0
- data/lib/ibex/lalr/ielr/inadequacy.rb +47 -0
- data/lib/ibex/lalr/ielr/item_lookaheads.rb +78 -0
- data/lib/ibex/lalr/ielr/pipeline.rb +75 -0
- data/lib/ibex/lalr/ielr/split_stability.rb +78 -0
- data/lib/ibex/lalr/ielr/split_state.rb +20 -0
- data/lib/ibex/lalr/ielr/state_splitter.rb +258 -0
- data/lib/ibex/lalr/ielr_partition.rb +22 -8
- data/lib/ibex/lalr/inadequacy_report.rb +50 -0
- data/lib/ibex/lalr/lookahead_propagation.rb +111 -0
- data/lib/ibex/lalr/lr0_collection.rb +121 -0
- data/lib/ibex/lalr/unreachable_states.rb +80 -0
- data/lib/ibex/lalr.rb +52 -1
- data/lib/ibex/location.rb +3 -3
- data/lib/ibex/lsp/document_handlers.rb +9 -7
- data/lib/ibex/lsp/initialization_handlers.rb +9 -7
- data/lib/ibex/lsp/navigation_handlers.rb +25 -11
- data/lib/ibex/lsp/parser_configuration_assistance.rb +149 -0
- data/lib/ibex/lsp/position_codec.rb +6 -2
- data/lib/ibex/lsp/request_handlers.rb +3 -2
- data/lib/ibex/lsp/request_support.rb +14 -7
- data/lib/ibex/lsp/server.rb +13 -11
- data/lib/ibex/lsp/symbol_index.rb +13 -13
- data/lib/ibex/lsp/symbol_index_builder.rb +30 -20
- data/lib/ibex/lsp/symbol_occurrence.rb +8 -2
- data/lib/ibex/lsp/transport.rb +13 -3
- data/lib/ibex/lsp/workspace.rb +5 -4
- data/lib/ibex/lsp/workspace_analyzer.rb +1 -1
- data/lib/ibex/lsp.rb +1 -0
- data/lib/ibex/messages/en.yml +28 -0
- data/lib/ibex/messages/ja.yml +28 -0
- data/lib/ibex/messages.rb +68 -0
- data/lib/ibex/metrics.rb +175 -0
- data/lib/ibex/normalize/declarations.rb +2 -0
- data/lib/ibex/normalize/diagnostics.rb +63 -38
- data/lib/ibex/normalize/expander.rb +5 -4
- data/lib/ibex/normalize/expression.rb +8 -6
- data/lib/ibex/normalize/grammar_builder.rb +26 -0
- data/lib/ibex/normalize/inline_expansion.rb +100 -49
- data/lib/ibex/normalize/lexer.rb +3 -3
- data/lib/ibex/normalize/parameter_ebnf_lowering.rb +11 -10
- data/lib/ibex/normalize/parameter_lowering.rb +40 -23
- data/lib/ibex/normalize/parameters.rb +31 -4
- data/lib/ibex/normalize/parser_configuration.rb +70 -0
- data/lib/ibex/normalize.rb +10 -20
- data/lib/ibex/racc_migration/report.rb +6 -3
- data/lib/ibex/rake_task.rb +1 -1
- data/lib/ibex/samples.rb +43 -13
- data/lib/ibex/table_artifact/builder.rb +266 -0
- data/lib/ibex/table_artifact/cst_projection.rb +70 -0
- data/lib/ibex/table_artifact/document.rb +39 -0
- data/lib/ibex/table_artifact/executor.rb +187 -0
- data/lib/ibex/table_artifact/serializer.rb +57 -0
- data/lib/ibex/table_artifact/validator/metadata.rb +179 -0
- data/lib/ibex/table_artifact/validator/support.rb +86 -0
- data/lib/ibex/table_artifact/validator/tables.rb +238 -0
- data/lib/ibex/table_artifact/validator.rb +253 -0
- data/lib/ibex/table_artifact.rb +88 -0
- data/lib/ibex/table_simulation/result.rb +6 -2
- data/lib/ibex/table_simulation/step.rb +3 -1
- data/lib/ibex/tables.rb +14 -0
- data/lib/ibex/verifiable_generation_bundle.rb +86 -0
- data/lib/ibex/verification_report/builder.rb +159 -0
- data/lib/ibex/verification_report/canonical_ir.rb +123 -0
- data/lib/ibex/verification_report/logical_path.rb +68 -0
- data/lib/ibex/verification_report/validator.rb +329 -0
- data/lib/ibex/verification_report.rb +69 -0
- data/lib/ibex/verify/action_correspondence.rb +138 -0
- data/lib/ibex/verify/language_witness.rb +295 -0
- data/lib/ibex/verify/reference_collection.rb +190 -0
- data/lib/ibex/verify/result.rb +73 -0
- data/lib/ibex/verify/verifier.rb +598 -0
- data/lib/ibex/verify.rb +15 -0
- data/lib/ibex/version.rb +1 -1
- data/lib/ibex/watch/runner.rb +10 -1
- data/lib/ibex/watch/source_snapshot.rb +13 -8
- data/lib/ibex.rb +10 -0
- data/schema/{automaton-ir-v1.schema.json → automaton-ir-definitions.schema.json} +6 -6
- data/schema/{automaton-ir-v2.schema.json → automaton-ir.schema.json} +14 -7
- data/schema/bison-import-v1.schema.json +106 -0
- data/schema/conflict-explanation-review-v1.schema.json +196 -0
- data/schema/conflict-explanation-study-v1.schema.json +528 -0
- data/schema/construction-profile-v1.schema.json +779 -0
- data/schema/diff-v1.schema.json +41 -0
- data/schema/direct-ielr-decision-v1.schema.json +200 -0
- data/schema/equiv-v1.schema.json +64 -0
- data/schema/error-ux-review-v1.schema.json +609 -0
- data/schema/error-ux-round2-review-v1.schema.json +191 -0
- data/schema/error-ux-round2-v1.schema.json +519 -0
- data/schema/explain-v1.schema.json +63 -1
- data/schema/fix-v1.schema.json +64 -0
- data/schema/fix-v2.schema.json +66 -0
- data/schema/fix-v3.schema.json +101 -0
- data/schema/fuzz-regression-v1.schema.json +79 -0
- data/schema/fuzz-v1.schema.json +114 -0
- data/schema/{grammar-ir-v2.schema.json → grammar-ir-extensions.schema.json} +20 -65
- data/schema/{grammar-ir-v1.schema.json → grammar-ir-foundation.schema.json} +3 -3
- data/schema/grammar-ir.schema.json +271 -0
- data/schema/ielr-benchmark-v1.schema.json +85 -0
- data/schema/lexer-profile-v1.schema.json +491 -0
- data/schema/metrics-v1.schema.json +60 -0
- data/schema/reduce-v1.schema.json +22 -0
- data/schema/reduce-v2.schema.json +63 -0
- data/schema/table-artifact-v1.schema.json +377 -0
- data/schema/verification-report-v1.schema.json +222 -0
- data/schema/verify-v1.schema.json +42 -0
- data/sig/ibex/analysis/digraph.rbs +19 -0
- data/sig/ibex/bison_import/importer.rbs +140 -0
- data/sig/ibex/bison_import/tokenizer.rbs +91 -0
- data/sig/ibex/bison_import.rbs +95 -0
- data/sig/ibex/bounded_subprocess.rbs +76 -0
- data/sig/ibex/cli/ambiguity.rbs +6 -0
- data/sig/ibex/cli/analysis.rbs +43 -0
- data/sig/ibex/cli/bison_import.rbs +32 -0
- data/sig/ibex/cli/config.rbs +35 -0
- data/sig/ibex/cli/diagnostics.rbs +16 -3
- data/sig/ibex/cli/documentation.rbs +5 -1
- data/sig/ibex/cli/equiv.rbs +49 -0
- data/sig/ibex/cli/error_messages.rbs +6 -0
- data/sig/ibex/cli/explain.rbs +6 -0
- data/sig/ibex/cli/fix.rbs +53 -0
- data/sig/ibex/cli/formatting.rbs +5 -1
- data/sig/ibex/cli/fuzz.rbs +47 -0
- data/sig/ibex/cli/fuzz_regressions.rbs +40 -0
- data/sig/ibex/cli/generation_artifacts.rbs +21 -2
- data/sig/ibex/cli/generation_error_messages.rbs +2 -2
- data/sig/ibex/cli/grammar_tests.rbs +15 -3
- data/sig/ibex/cli/ir_tools.rbs +7 -19
- data/sig/ibex/cli/outputs.rbs +9 -3
- data/sig/ibex/cli/reduce.rbs +60 -0
- data/sig/ibex/cli/reduce_reporting.rbs +27 -0
- data/sig/ibex/cli/samples.rbs +8 -0
- data/sig/ibex/cli/verify.rbs +28 -0
- data/sig/ibex/cli/watch.rbs +2 -2
- data/sig/ibex/cli.rbs +79 -5
- data/sig/ibex/codegen/action_method_source.rbs +4 -4
- data/sig/ibex/codegen/explain.rbs +45 -25
- data/sig/ibex/codegen/generated_action_abi.rbs +14 -10
- data/sig/ibex/codegen/rbs.rbs +12 -10
- data/sig/ibex/codegen/report.rbs +12 -12
- data/sig/ibex/codegen/ruby.rbs +18 -15
- data/sig/ibex/codegen/ruby_actions.rbs +6 -6
- data/sig/ibex/codegen/ruby_syntax.rbs +10 -8
- data/sig/ibex/configuration/analysis_grammar.rbs +13 -0
- data/sig/ibex/configuration/explanation.rbs +195 -0
- data/sig/ibex/configuration/inspector.rbs +53 -0
- data/sig/ibex/configuration.rbs +242 -0
- data/sig/ibex/coverage/collector.rbs +16 -14
- data/sig/ibex/coverage/event_stream.rbs +12 -10
- data/sig/ibex/coverage/report.rbs +20 -18
- data/sig/ibex/coverage/runtime_event_validator.rbs +38 -36
- data/sig/ibex/delta_reducer.rbs +38 -0
- data/sig/ibex/diff.rbs +47 -0
- data/sig/ibex/equiv/machine.rbs +54 -0
- data/sig/ibex/equiv.rbs +129 -0
- data/sig/ibex/fix.rbs +138 -0
- data/sig/ibex/frontend/ast.rbs +33 -7
- data/sig/ibex/frontend/bootstrap_parser.rbs +2 -0
- data/sig/ibex/frontend/diagnostic.rbs +2 -2
- data/sig/ibex/frontend/formatter.rbs +38 -30
- data/sig/ibex/frontend/generated_parser.rbs +87 -77
- data/sig/ibex/frontend/generated_parser_base.rbs +4 -2
- data/sig/ibex/frontend/parser/declarations.rbs +3 -0
- data/sig/ibex/frontend/parser_configuration_support.rbs +27 -0
- data/sig/ibex/frontend/resolution.rbs +3 -2
- data/sig/ibex/frontend/source_cursor.rbs +2 -2
- data/sig/ibex/frontend/source_span.rbs +5 -2
- data/sig/ibex/frontend/token_adapter/declaration_state.rbs +13 -1
- data/sig/ibex/frontend/token_adapter.rbs +6 -0
- data/sig/ibex/fuzz.rbs +71 -0
- data/sig/ibex/generation_input.rbs +2 -2
- data/sig/ibex/generation_manifest.rbs +35 -32
- data/sig/ibex/generation_transaction_recovery.rbs +2 -2
- data/sig/ibex/generation_transaction_validation.rbs +2 -2
- data/sig/ibex/grammar_tests.rbs +2 -2
- data/sig/ibex/ir/automaton_ir.rbs +30 -11
- data/sig/ibex/ir/grammar_ir.rbs +41 -27
- data/sig/ibex/ir/lexer_ir.rbs +8 -8
- data/sig/ibex/ir/parser_contract.rbs +69 -0
- data/sig/ibex/ir/serialize.rbs +63 -28
- data/sig/ibex/ir/validator/automaton.rbs +47 -44
- data/sig/ibex/ir/validator/base.rbs +35 -31
- data/sig/ibex/ir/validator/grammar.rbs +78 -67
- data/sig/ibex/ir/validator/lexer.rbs +4 -4
- data/sig/ibex/ir.rbs +9 -3
- data/sig/ibex/lalr/build_metrics.rbs +42 -2
- data/sig/ibex/lalr/builder.rbs +75 -24
- data/sig/ibex/lalr/conflict_search.rbs +5 -2
- data/sig/ibex/lalr/counterexample.rbs +17 -14
- data/sig/ibex/lalr/direct_lookaheads.rbs +35 -28
- data/sig/ibex/lalr/goto_follows.rbs +89 -0
- data/sig/ibex/lalr/ielr/annotator.rbs +67 -0
- data/sig/ibex/lalr/ielr/bits.rbs +14 -0
- data/sig/ibex/lalr/ielr/inadequacy.rbs +24 -0
- data/sig/ibex/lalr/ielr/item_lookaheads.rbs +35 -0
- data/sig/ibex/lalr/ielr/pipeline.rbs +17 -0
- data/sig/ibex/lalr/ielr/split_stability.rbs +27 -0
- data/sig/ibex/lalr/ielr/split_state.rbs +14 -0
- data/sig/ibex/lalr/ielr/state_splitter.rbs +76 -0
- data/sig/ibex/lalr/ielr_partition.rbs +17 -5
- data/sig/ibex/lalr/inadequacy_report.rbs +21 -0
- data/sig/ibex/lalr/lookahead_propagation.rbs +38 -0
- data/sig/ibex/lalr/lr0_collection.rbs +50 -0
- data/sig/ibex/lalr/unreachable_states.rbs +25 -0
- data/sig/ibex/lalr.rbs +11 -1
- data/sig/ibex/location.rbs +6 -6
- data/sig/ibex/lsp/document_handlers.rbs +8 -8
- data/sig/ibex/lsp/initialization_handlers.rbs +12 -12
- data/sig/ibex/lsp/navigation_handlers.rbs +15 -12
- data/sig/ibex/lsp/parser_configuration_assistance.rbs +49 -0
- data/sig/ibex/lsp/position_codec.rbs +8 -4
- data/sig/ibex/lsp/request_handlers.rbs +4 -4
- data/sig/ibex/lsp/request_support.rbs +8 -8
- data/sig/ibex/lsp/server.rbs +16 -16
- data/sig/ibex/lsp/symbol_index.rbs +20 -21
- data/sig/ibex/lsp/symbol_index_builder.rbs +9 -8
- data/sig/ibex/lsp/symbol_occurrence.rbs +11 -5
- data/sig/ibex/lsp/transport.rbs +18 -6
- data/sig/ibex/lsp/workspace.rbs +3 -2
- data/sig/ibex/lsp/workspace_analyzer.rbs +1 -1
- data/sig/ibex/messages.rbs +26 -0
- data/sig/ibex/metrics.rbs +50 -0
- data/sig/ibex/normalize/diagnostics.rbs +4 -4
- data/sig/ibex/normalize/expander.rbs +2 -2
- data/sig/ibex/normalize/expression.rbs +10 -8
- data/sig/ibex/normalize/grammar_builder.rbs +11 -0
- data/sig/ibex/normalize/inline_expansion.rbs +59 -50
- data/sig/ibex/normalize/lexer.rbs +4 -4
- data/sig/ibex/normalize/parameter_ebnf_lowering.rbs +15 -14
- data/sig/ibex/normalize/parameter_lowering.rbs +18 -18
- data/sig/ibex/normalize/parameters.rbs +13 -8
- data/sig/ibex/normalize/parser_configuration.rbs +23 -0
- data/sig/ibex/normalize.rbs +11 -5
- data/sig/ibex/racc_migration/report.rbs +8 -6
- data/sig/ibex/rake_task.rbs +1 -1
- data/sig/ibex/samples.rbs +13 -4
- data/sig/ibex/table_artifact/builder.rbs +93 -0
- data/sig/ibex/table_artifact/cst_projection.rbs +20 -0
- data/sig/ibex/table_artifact/document.rbs +27 -0
- data/sig/ibex/table_artifact/executor.rbs +66 -0
- data/sig/ibex/table_artifact/serializer.rbs +25 -0
- data/sig/ibex/table_artifact/validator/metadata.rbs +52 -0
- data/sig/ibex/table_artifact/validator/support.rbs +46 -0
- data/sig/ibex/table_artifact/validator/tables.rbs +63 -0
- data/sig/ibex/table_artifact/validator.rbs +66 -0
- data/sig/ibex/table_artifact.rbs +32 -0
- data/sig/ibex/table_simulation/result.rbs +8 -4
- data/sig/ibex/table_simulation/step.rbs +4 -2
- data/sig/ibex/tables.rbs +10 -9
- data/sig/ibex/verifiable_generation_bundle.rbs +24 -0
- data/sig/ibex/verification_report/builder.rbs +53 -0
- data/sig/ibex/verification_report/canonical_ir.rbs +41 -0
- data/sig/ibex/verification_report/logical_path.rbs +34 -0
- data/sig/ibex/verification_report/validator.rbs +114 -0
- data/sig/ibex/verification_report.rbs +44 -0
- data/sig/ibex/verify/action_correspondence.rbs +50 -0
- data/sig/ibex/verify/language_witness.rbs +112 -0
- data/sig/ibex/verify/reference_collection.rbs +63 -0
- data/sig/ibex/verify/result.rbs +52 -0
- data/sig/ibex/verify/verifier.rbs +170 -0
- data/sig/ibex/verify.rbs +6 -0
- data/sig/ibex/watch/runner.rbs +12 -2
- data/sig/ibex/watch/source_snapshot.rbs +13 -9
- metadata +232 -12
- data/lib/ibex/ir/migration.rb +0 -120
- data/sig/ibex/ir/migration.rbs +0 -34
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
require "json"
|
|
5
|
+
require_relative "error"
|
|
6
|
+
require_relative "location"
|
|
7
|
+
|
|
8
|
+
module Ibex
|
|
9
|
+
# Typed, provenance-preserving effective configuration.
|
|
10
|
+
module Configuration
|
|
11
|
+
# @rbs!
|
|
12
|
+
# type config_value = Symbol | String | Integer | bool | nil
|
|
13
|
+
# type json_value = String | Integer | bool | nil | Array[json_value] | Hash[String, json_value]
|
|
14
|
+
|
|
15
|
+
OWNER_NAMES = {
|
|
16
|
+
grammar_contract: "grammar-contract",
|
|
17
|
+
grammar_minimum: "grammar-minimum",
|
|
18
|
+
project_build: "project-build",
|
|
19
|
+
invocation: "invocation"
|
|
20
|
+
}.freeze #: Hash[Symbol, String]
|
|
21
|
+
POLICIES = %i[fixed minimum build invocation].freeze #: Array[Symbol]
|
|
22
|
+
ORIGIN_KINDS = %i[builtin grammar project cli analysis_override].freeze #: Array[Symbol]
|
|
23
|
+
BOOLEAN_VALUES = [true, false].freeze #: Array[bool]
|
|
24
|
+
DECLARED_VALUE_UNSET = Object.new.freeze #: Object
|
|
25
|
+
OWNER_POLICIES = {
|
|
26
|
+
grammar_contract: :fixed, grammar_minimum: :minimum,
|
|
27
|
+
project_build: :build, invocation: :invocation
|
|
28
|
+
}.freeze #: Hash[Symbol, Symbol]
|
|
29
|
+
|
|
30
|
+
# One closed definition of a configuration concept and its value domain.
|
|
31
|
+
class Key
|
|
32
|
+
attr_reader :name #: String
|
|
33
|
+
attr_reader :type #: Symbol
|
|
34
|
+
attr_reader :default #: config_value
|
|
35
|
+
attr_reader :owner #: Symbol
|
|
36
|
+
attr_reader :policy #: Symbol
|
|
37
|
+
attr_reader :allowed_values #: Array[config_value]?
|
|
38
|
+
attr_reader :cli_option #: Symbol?
|
|
39
|
+
|
|
40
|
+
# @rbs (String name, type: Symbol, default: config_value, owner: Symbol, policy: Symbol,
|
|
41
|
+
# ?allowed_values: Array[config_value]?, ?cli_option: Symbol?) -> void
|
|
42
|
+
def initialize(name, type:, default:, owner:, policy:, allowed_values: nil, cli_option: nil)
|
|
43
|
+
validate_identity!(name, owner, policy)
|
|
44
|
+
validate_shape!(type, policy, cli_option)
|
|
45
|
+
|
|
46
|
+
@name = name.dup.freeze
|
|
47
|
+
@type = type
|
|
48
|
+
@owner = owner
|
|
49
|
+
@policy = policy
|
|
50
|
+
@allowed_values = allowed_values&.map { |value| immutable(value) }&.freeze
|
|
51
|
+
@cli_option = cli_option
|
|
52
|
+
@default = validate(default)
|
|
53
|
+
freeze
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Validate and defensively freeze a value from an adapter or declaration.
|
|
57
|
+
# @rbs (config_value value) -> config_value
|
|
58
|
+
def validate(value)
|
|
59
|
+
raise ArgumentError, "#{@name} expects #{@type}, got #{value.inspect}" unless valid_type?(value)
|
|
60
|
+
|
|
61
|
+
allowed_values = @allowed_values
|
|
62
|
+
if allowed_values && !allowed_values.include?(value)
|
|
63
|
+
raise ArgumentError, "#{@name} must be one of #{allowed_values.map(&:inspect).join(', ')}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
immutable(value)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @rbs () -> String
|
|
70
|
+
def owner_name
|
|
71
|
+
OWNER_NAMES.fetch(@owner)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
# @rbs (String name, Symbol owner, Symbol policy) -> void
|
|
77
|
+
def validate_identity!(name, owner, policy)
|
|
78
|
+
valid_name = name.is_a?(String) && name.match?(/\A[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)+\z/)
|
|
79
|
+
raise ArgumentError, "invalid canonical configuration key: #{name.inspect}" unless valid_name
|
|
80
|
+
raise ArgumentError, "unknown configuration owner: #{owner.inspect}" unless OWNER_NAMES.key?(owner)
|
|
81
|
+
raise ArgumentError, "unknown configuration policy: #{policy.inspect}" unless POLICIES.include?(policy)
|
|
82
|
+
return if OWNER_POLICIES.fetch(owner) == policy
|
|
83
|
+
|
|
84
|
+
raise ArgumentError, "#{owner} configuration must use #{OWNER_POLICIES.fetch(owner)} policy"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# @rbs (Symbol type, Symbol policy, Symbol? cli_option) -> void
|
|
88
|
+
def validate_shape!(type, policy, cli_option)
|
|
89
|
+
raise ArgumentError, "cli_option must be a Symbol or nil" unless cli_option.nil? || cli_option.is_a?(Symbol)
|
|
90
|
+
return unless policy == :minimum && type != :integer
|
|
91
|
+
|
|
92
|
+
raise ArgumentError, "minimum configuration keys must have Integer values"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# @rbs (config_value value) -> config_value
|
|
96
|
+
def immutable(value)
|
|
97
|
+
value.is_a?(String) ? value.dup.freeze : value
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# @rbs (config_value value) -> bool
|
|
101
|
+
def valid_type?(value)
|
|
102
|
+
case @type
|
|
103
|
+
when :symbol then value.is_a?(Symbol)
|
|
104
|
+
when :boolean then BOOLEAN_VALUES.include?(value)
|
|
105
|
+
when :integer then value.is_a?(Integer)
|
|
106
|
+
when :optional_boolean then value.nil? || BOOLEAN_VALUES.include?(value)
|
|
107
|
+
when :optional_string then value.nil? || value.is_a?(String)
|
|
108
|
+
else raise ArgumentError, "unknown configuration value type: #{@type.inspect}"
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Where a selected configuration value came from.
|
|
114
|
+
class Origin
|
|
115
|
+
attr_reader :kind #: Symbol
|
|
116
|
+
attr_reader :location #: Location?
|
|
117
|
+
|
|
118
|
+
# @rbs (Symbol kind, ?location: Location?) -> void
|
|
119
|
+
def initialize(kind, location: nil)
|
|
120
|
+
raise ArgumentError, "unknown configuration origin: #{kind.inspect}" unless ORIGIN_KINDS.include?(kind)
|
|
121
|
+
unless location.nil? || location.is_a?(Location)
|
|
122
|
+
raise ArgumentError, "configuration location must be an Ibex::Location"
|
|
123
|
+
end
|
|
124
|
+
if location && !%i[grammar project].include?(kind)
|
|
125
|
+
raise ArgumentError, "#{kind} configuration cannot have a source location"
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
@kind = kind
|
|
129
|
+
@location = location
|
|
130
|
+
freeze
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# @rbs () -> Hash[String, json_value]
|
|
134
|
+
def to_h
|
|
135
|
+
result = { "kind" => @kind.to_s } #: Hash[String, json_value]
|
|
136
|
+
location = @location
|
|
137
|
+
result["location"] = stringify_location(location) if location
|
|
138
|
+
result
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# @rbs () -> String
|
|
142
|
+
def label
|
|
143
|
+
location = @location
|
|
144
|
+
return @kind.to_s unless location
|
|
145
|
+
|
|
146
|
+
file = location.file || "(source)"
|
|
147
|
+
"#{@kind} #{file}:#{location.line}:#{location.column}"
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
private
|
|
151
|
+
|
|
152
|
+
# @rbs (Location location) -> Hash[String, json_value]
|
|
153
|
+
def stringify_location(location)
|
|
154
|
+
location.to_h.transform_keys(&:to_s)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# A typed effective value plus the evidence needed to explain it.
|
|
159
|
+
class Value
|
|
160
|
+
attr_reader :key #: Key
|
|
161
|
+
attr_reader :value #: config_value
|
|
162
|
+
attr_reader :origin #: Origin
|
|
163
|
+
attr_reader :explicit #: bool
|
|
164
|
+
attr_reader :canonical #: bool
|
|
165
|
+
attr_reader :declared_value #: config_value
|
|
166
|
+
|
|
167
|
+
# @rbs (Key key, config_value value, origin: Origin, explicit: bool, canonical: bool,
|
|
168
|
+
# ?declared_value: config_value | Object) -> void
|
|
169
|
+
def initialize(key, value, origin:, explicit:, canonical:, declared_value: DECLARED_VALUE_UNSET)
|
|
170
|
+
raise ArgumentError, "configuration value key must be a Configuration::Key" unless key.is_a?(Key)
|
|
171
|
+
raise ArgumentError, "configuration value origin must be a Configuration::Origin" unless origin.is_a?(Origin)
|
|
172
|
+
raise ArgumentError, "explicit must be boolean" unless BOOLEAN_VALUES.include?(explicit)
|
|
173
|
+
raise ArgumentError, "canonical must be boolean" unless BOOLEAN_VALUES.include?(canonical)
|
|
174
|
+
|
|
175
|
+
validate_provenance!(key, origin, explicit, canonical, declared_value)
|
|
176
|
+
|
|
177
|
+
@key = key
|
|
178
|
+
@value = key.validate(value)
|
|
179
|
+
@origin = origin
|
|
180
|
+
@explicit = explicit
|
|
181
|
+
@canonical = canonical
|
|
182
|
+
declared = declared_value #: config_value
|
|
183
|
+
@declared_value = declared.equal?(DECLARED_VALUE_UNSET) ? nil : key.validate(declared)
|
|
184
|
+
|
|
185
|
+
freeze
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# @rbs () -> Hash[String, json_value]
|
|
189
|
+
def to_h
|
|
190
|
+
result = {
|
|
191
|
+
"key" => @key.name,
|
|
192
|
+
"value" => json_value(@value),
|
|
193
|
+
"owner" => @key.owner_name,
|
|
194
|
+
"policy" => @key.policy.to_s,
|
|
195
|
+
"origin" => @origin.to_h,
|
|
196
|
+
"explicit" => @explicit,
|
|
197
|
+
"canonical" => @canonical
|
|
198
|
+
} #: Hash[String, json_value]
|
|
199
|
+
unless @canonical
|
|
200
|
+
result["analysis"] = {
|
|
201
|
+
"declared" => json_value(@declared_value),
|
|
202
|
+
"selected" => json_value(@value),
|
|
203
|
+
"override" => true,
|
|
204
|
+
"canonical_generation" => false
|
|
205
|
+
}
|
|
206
|
+
end
|
|
207
|
+
result
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
private
|
|
211
|
+
|
|
212
|
+
# @rbs (Key key, Origin origin, bool explicit, bool canonical, config_value | Object declared_value) -> void
|
|
213
|
+
def validate_provenance!(key, origin, explicit, canonical, declared_value)
|
|
214
|
+
validate_canonical_origin!(key, origin, canonical)
|
|
215
|
+
validate_owner_source!(key, origin)
|
|
216
|
+
validate_explicitness!(origin, explicit)
|
|
217
|
+
validate_declared_evidence!(canonical, declared_value)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# @rbs (Key key, Origin origin, bool canonical) -> void
|
|
221
|
+
def validate_canonical_origin!(key, origin, canonical)
|
|
222
|
+
analysis_override = origin.kind == :analysis_override
|
|
223
|
+
unless analysis_override == !canonical
|
|
224
|
+
raise ArgumentError, "analysis_override origin must identify a noncanonical selection"
|
|
225
|
+
end
|
|
226
|
+
return if canonical || key.policy == :fixed
|
|
227
|
+
|
|
228
|
+
raise ArgumentError, "noncanonical selections are only valid for fixed configuration"
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# @rbs (Key key, Origin origin) -> void
|
|
232
|
+
def validate_owner_source!(key, origin)
|
|
233
|
+
if origin.kind == :grammar && !%i[fixed minimum].include?(key.policy)
|
|
234
|
+
raise ArgumentError, "#{key.name} is #{key.policy} configuration and cannot be grammar-owned"
|
|
235
|
+
end
|
|
236
|
+
return unless origin.kind == :project && key.policy == :invocation
|
|
237
|
+
|
|
238
|
+
raise ArgumentError, "#{key.name} is invocation configuration and cannot be project-owned"
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# @rbs (Origin origin, bool explicit) -> void
|
|
242
|
+
def validate_explicitness!(origin, explicit)
|
|
243
|
+
raise ArgumentError, "builtin configuration cannot be explicit" if origin.kind == :builtin && explicit
|
|
244
|
+
raise ArgumentError, "non-builtin configuration must be explicit" if origin.kind != :builtin && !explicit
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# @rbs (bool canonical, config_value | Object declared_value) -> void
|
|
248
|
+
def validate_declared_evidence!(canonical, declared_value)
|
|
249
|
+
declared = !declared_value.equal?(DECLARED_VALUE_UNSET)
|
|
250
|
+
raise ArgumentError, "canonical selections cannot carry declared evidence" if canonical && declared
|
|
251
|
+
return if canonical || declared
|
|
252
|
+
|
|
253
|
+
raise ArgumentError, "noncanonical selections require declared evidence"
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# @rbs (config_value value) -> (String | Integer | bool | nil)
|
|
257
|
+
def json_value(value)
|
|
258
|
+
value.is_a?(Symbol) ? value.to_s : value
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# A fixed/minimum request that contradicts the declared contract.
|
|
263
|
+
class Conflict < Ibex::Error
|
|
264
|
+
attr_reader :key #: Key
|
|
265
|
+
attr_reader :declared #: Value
|
|
266
|
+
attr_reader :requested #: Value
|
|
267
|
+
|
|
268
|
+
# @rbs (Key key, Value declared, Value requested) -> void
|
|
269
|
+
def initialize(key, declared, requested)
|
|
270
|
+
@key = key
|
|
271
|
+
@declared = declared
|
|
272
|
+
@requested = requested
|
|
273
|
+
super(
|
|
274
|
+
"configuration conflict for #{key.name}: " \
|
|
275
|
+
"#{declared.origin.label} selected #{declared.value.inspect}, " \
|
|
276
|
+
"#{requested.origin.label} requested #{requested.value.inspect}"
|
|
277
|
+
)
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Closed definitions shared by generation, grammar tests, and analyses.
|
|
282
|
+
module Registry
|
|
283
|
+
DEFINITIONS = [
|
|
284
|
+
Key.new("grammar.mode", type: :symbol, default: :default, owner: :grammar_contract, policy: :fixed,
|
|
285
|
+
allowed_values: %i[default extended], cli_option: :mode),
|
|
286
|
+
Key.new("parser.algorithm", type: :symbol, default: :lalr, owner: :grammar_contract, policy: :fixed,
|
|
287
|
+
allowed_values: %i[slr lalr ielr lr1], cli_option: :algorithm),
|
|
288
|
+
Key.new("parser.entries", type: :symbol, default: :shared, owner: :grammar_contract, policy: :fixed,
|
|
289
|
+
allowed_values: %i[shared isolated], cli_option: :entry_isolation),
|
|
290
|
+
Key.new("cst.trivia", type: :symbol, default: :leading, owner: :grammar_contract, policy: :fixed,
|
|
291
|
+
allowed_values: %i[leading balanced drop], cli_option: :cst_trivia),
|
|
292
|
+
Key.new("parser.superclass", type: :optional_string, default: nil, owner: :grammar_contract, policy: :fixed,
|
|
293
|
+
cli_option: :superclass),
|
|
294
|
+
Key.new("actions.omit_calls", type: :optional_boolean, default: nil, owner: :grammar_contract,
|
|
295
|
+
policy: :fixed, cli_option: :omit_actions),
|
|
296
|
+
Key.new("table.representation", type: :symbol, default: :compact, owner: :project_build, policy: :build,
|
|
297
|
+
allowed_values: %i[plain compact], cli_option: :table),
|
|
298
|
+
Key.new("runtime.embedded", type: :boolean, default: false, owner: :project_build, policy: :build,
|
|
299
|
+
cli_option: :embedded),
|
|
300
|
+
Key.new("build.debug", type: :boolean, default: false, owner: :project_build, policy: :build,
|
|
301
|
+
cli_option: :debug),
|
|
302
|
+
Key.new("source.line_mapping", type: :symbol, default: :actions, owner: :project_build, policy: :build,
|
|
303
|
+
allowed_values: %i[actions all none], cli_option: :line_convert),
|
|
304
|
+
Key.new("build.frozen_strings", type: :boolean, default: false, owner: :project_build, policy: :build,
|
|
305
|
+
cli_option: :frozen),
|
|
306
|
+
Key.new("build.executable", type: :optional_string, default: nil, owner: :project_build, policy: :build,
|
|
307
|
+
cli_option: :executable)
|
|
308
|
+
].freeze #: Array[Key]
|
|
309
|
+
BY_NAME = DEFINITIONS.to_h { |key| [key.name, key] }.freeze #: Hash[String, Key]
|
|
310
|
+
|
|
311
|
+
class << self
|
|
312
|
+
# @rbs (String name) -> Key
|
|
313
|
+
def fetch(name)
|
|
314
|
+
BY_NAME.fetch(name) { raise ArgumentError, "unknown configuration key: #{name.inspect}" }
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# @rbs () -> Array[Key]
|
|
318
|
+
def keys
|
|
319
|
+
DEFINITIONS
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# Applies fixed/minimum override algebra and exposes deterministic evidence.
|
|
325
|
+
class Resolver
|
|
326
|
+
attr_reader :values #: Array[Value]
|
|
327
|
+
|
|
328
|
+
# @rbs (?keys: Array[Key], ?grammar: Hash[String, config_value], ?project: Hash[String, config_value],
|
|
329
|
+
# ?cli: Hash[String, config_value], ?analysis_overrides: Hash[String, config_value],
|
|
330
|
+
# ?locations: Hash[Symbol, Hash[String, Location]]) -> void
|
|
331
|
+
def initialize(keys: Registry.keys, grammar: {}, project: {}, cli: {}, analysis_overrides: {}, locations: {})
|
|
332
|
+
@keys = keys.sort_by(&:name).freeze
|
|
333
|
+
@key_index = @keys.to_h { |key| [key.name, key] }.freeze
|
|
334
|
+
raise ArgumentError, "duplicate configuration key definition" unless @key_index.length == @keys.length
|
|
335
|
+
|
|
336
|
+
sources = { grammar: grammar, project: project, cli: cli, analysis_override: analysis_overrides }
|
|
337
|
+
sources.each { |kind, entries| validate_source!(kind, entries) }
|
|
338
|
+
validate_locations!(locations, sources)
|
|
339
|
+
@values = @keys.map do |key|
|
|
340
|
+
resolve_key(key, sources, locations)
|
|
341
|
+
end.freeze
|
|
342
|
+
@value_index = @values.to_h { |entry| [entry.key.name, entry] }.freeze
|
|
343
|
+
freeze
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
# @rbs (String name) -> Value
|
|
347
|
+
def fetch(name)
|
|
348
|
+
@value_index.fetch(name) { raise ArgumentError, "unknown configuration key: #{name.inspect}" }
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
# @rbs (String name) -> config_value
|
|
352
|
+
def value(name)
|
|
353
|
+
fetch(name).value
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# @rbs () -> Hash[String, Array[Hash[String, json_value]]]
|
|
357
|
+
def to_h
|
|
358
|
+
{ "configuration" => @values.map(&:to_h) }
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
# Deterministic JSON independent of caller hash insertion order.
|
|
362
|
+
# @rbs () -> String
|
|
363
|
+
def dump
|
|
364
|
+
"#{JSON.generate(to_h)}\n"
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
private
|
|
368
|
+
|
|
369
|
+
# @rbs (Symbol kind, Hash[String, config_value] entries) -> void
|
|
370
|
+
def validate_source!(kind, entries)
|
|
371
|
+
entries.each_key do |name|
|
|
372
|
+
raise ArgumentError, "unknown #{kind} configuration key: #{name.inspect}" unless @key_index.key?(name)
|
|
373
|
+
end
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
# @rbs (Hash[Symbol, Hash[String, Location]] locations,
|
|
377
|
+
# Hash[Symbol, Hash[String, config_value]] sources) -> void
|
|
378
|
+
def validate_locations!(locations, sources)
|
|
379
|
+
locations.each do |kind, entries|
|
|
380
|
+
unless %i[grammar project].include?(kind)
|
|
381
|
+
raise ArgumentError, "#{kind} configuration cannot have source locations"
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
entries.each do |name, location|
|
|
385
|
+
raise ArgumentError, "unknown #{kind} configuration location: #{name.inspect}" unless @key_index.key?(name)
|
|
386
|
+
raise ArgumentError, "configuration location must be an Ibex::Location" unless location.is_a?(Location)
|
|
387
|
+
next if sources.fetch(kind).key?(name)
|
|
388
|
+
|
|
389
|
+
raise ArgumentError, "configuration location for #{name} has no #{kind} value"
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
# @rbs (Key key, Hash[Symbol, Hash[String, config_value]] sources,
|
|
395
|
+
# Hash[Symbol, Hash[String, Location]] locations) -> Value
|
|
396
|
+
def resolve_key(key, sources, locations)
|
|
397
|
+
builtin = value_from(key, key.default, :builtin, locations, explicit: false)
|
|
398
|
+
selected = case key.policy
|
|
399
|
+
when :fixed then resolve_fixed(key, builtin, sources, locations)
|
|
400
|
+
when :minimum then resolve_minimum(key, builtin, sources, locations)
|
|
401
|
+
when :build, :invocation then resolve_override(key, builtin, sources, locations)
|
|
402
|
+
else raise ArgumentError, "unsupported configuration policy: #{key.policy.inspect}"
|
|
403
|
+
end
|
|
404
|
+
override = sources.fetch(:analysis_override)
|
|
405
|
+
return selected unless override.key?(key.name)
|
|
406
|
+
raise ArgumentError, "analysis overrides are only valid for fixed configuration" unless key.policy == :fixed
|
|
407
|
+
if key.validate(override.fetch(key.name)) == selected.value
|
|
408
|
+
raise ArgumentError, "analysis override for #{key.name} must differ from the canonical value"
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
selected_origin = origin(:analysis_override, key.name, locations)
|
|
412
|
+
Value.new(
|
|
413
|
+
key, override.fetch(key.name), origin: selected_origin,
|
|
414
|
+
explicit: true, canonical: false, declared_value: selected.value
|
|
415
|
+
)
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
# @rbs (Key key, Value builtin, Hash[Symbol, Hash[String, config_value]] sources,
|
|
419
|
+
# Hash[Symbol, Hash[String, Location]] locations) -> Value
|
|
420
|
+
def resolve_fixed(key, builtin, sources, locations)
|
|
421
|
+
grammar = source_value(key, :grammar, sources, locations)
|
|
422
|
+
declared = grammar || builtin
|
|
423
|
+
requested = %i[project cli].filter_map { |kind| source_value(key, kind, sources, locations) }
|
|
424
|
+
reject_fixed_conflicts!(key, grammar, declared, requested)
|
|
425
|
+
|
|
426
|
+
grammar || requested.last || builtin
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
# @rbs (Key key, Value? grammar, Value declared, Array[Value] requested) -> void
|
|
430
|
+
def reject_fixed_conflicts!(key, grammar, declared, requested)
|
|
431
|
+
if grammar
|
|
432
|
+
conflict = requested.find { |selection| selection.value != declared.value }
|
|
433
|
+
raise Conflict.new(key, declared, conflict) if conflict
|
|
434
|
+
elsif requested.map(&:value).uniq.length > 1
|
|
435
|
+
raise Conflict.new(key, requested.fetch(0), requested.fetch(1))
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
# @rbs (Key key, Value builtin, Hash[Symbol, Hash[String, config_value]] sources,
|
|
440
|
+
# Hash[Symbol, Hash[String, Location]] locations) -> Value
|
|
441
|
+
def resolve_minimum(key, builtin, sources, locations)
|
|
442
|
+
grammar = source_value(key, :grammar, sources, locations)
|
|
443
|
+
floor = grammar || builtin
|
|
444
|
+
selected = floor
|
|
445
|
+
%i[project cli].each do |kind|
|
|
446
|
+
request = source_value(key, kind, sources, locations)
|
|
447
|
+
next unless request
|
|
448
|
+
|
|
449
|
+
request_value = request.value #: Integer
|
|
450
|
+
floor_value = floor.value #: Integer
|
|
451
|
+
raise Conflict.new(key, floor, request) if request_value < floor_value
|
|
452
|
+
|
|
453
|
+
selected_value = selected.value #: Integer
|
|
454
|
+
selected = request if request_value > selected_value
|
|
455
|
+
end
|
|
456
|
+
selected
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
# @rbs (Key key, Value builtin, Hash[Symbol, Hash[String, config_value]] sources,
|
|
460
|
+
# Hash[Symbol, Hash[String, Location]] locations) -> Value
|
|
461
|
+
def resolve_override(key, builtin, sources, locations)
|
|
462
|
+
if sources.fetch(:grammar).key?(key.name)
|
|
463
|
+
raise ArgumentError, "#{key.name} is #{key.policy} configuration and cannot be grammar-owned"
|
|
464
|
+
end
|
|
465
|
+
if key.policy == :invocation && sources.fetch(:project).key?(key.name)
|
|
466
|
+
raise ArgumentError, "#{key.name} is invocation configuration and cannot be project-owned"
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
source_value(key, :cli, sources, locations) ||
|
|
470
|
+
source_value(key, :project, sources, locations) || builtin
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
# @rbs (Key key, Symbol kind, Hash[Symbol, Hash[String, config_value]] sources,
|
|
474
|
+
# Hash[Symbol, Hash[String, Location]] locations) -> Value?
|
|
475
|
+
def source_value(key, kind, sources, locations)
|
|
476
|
+
entries = sources.fetch(kind)
|
|
477
|
+
return unless entries.key?(key.name)
|
|
478
|
+
|
|
479
|
+
value_from(key, entries.fetch(key.name), kind, locations, explicit: true)
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
# @rbs (Key key, config_value raw, Symbol kind, Hash[Symbol, Hash[String, Location]] locations,
|
|
483
|
+
# explicit: bool) -> Value
|
|
484
|
+
def value_from(key, raw, kind, locations, explicit:)
|
|
485
|
+
Value.new(
|
|
486
|
+
key, raw, origin: origin(kind, key.name, locations), explicit: explicit, canonical: true
|
|
487
|
+
)
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
# @rbs (Symbol kind, String name, Hash[Symbol, Hash[String, Location]] locations) -> Origin
|
|
491
|
+
def origin(kind, name, locations)
|
|
492
|
+
Origin.new(kind, location: locations.dig(kind, name))
|
|
493
|
+
end
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
# Converts the existing internal CLI option hash into canonical concepts.
|
|
497
|
+
class CLIAdapter
|
|
498
|
+
# The adapter receives the legacy CLI option map, which also contains
|
|
499
|
+
# operation flags and list values outside the closed configuration domain.
|
|
500
|
+
# It validates and converts only declared configuration options.
|
|
501
|
+
# @rbs (Hash[Symbol, untyped] options, ?explicit_keys: Array[Symbol]) -> void
|
|
502
|
+
def initialize(options, explicit_keys: options.keys)
|
|
503
|
+
@options = options.to_h do |name, value|
|
|
504
|
+
[name, value.is_a?(String) ? value.dup.freeze : value]
|
|
505
|
+
end.freeze
|
|
506
|
+
@explicit_keys = explicit_keys.dup.freeze
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
# @rbs (?grammar: Hash[String, config_value], ?locations: Hash[String, Location]) -> Resolver
|
|
510
|
+
def resolve(grammar: {}, locations: {})
|
|
511
|
+
source_locations = {} #: Hash[Symbol, Hash[String, Location]]
|
|
512
|
+
source_locations[:grammar] = locations unless locations.empty?
|
|
513
|
+
Resolver.new(grammar: grammar, cli: configuration_values, locations: source_locations)
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
# Canonical configuration values selected by explicit legacy CLI options.
|
|
517
|
+
# Raw option spellings stop at this adapter boundary.
|
|
518
|
+
# @rbs () -> Hash[String, config_value]
|
|
519
|
+
def configuration_values
|
|
520
|
+
options = {} #: Hash[String, config_value]
|
|
521
|
+
Registry::DEFINITIONS.each do |key|
|
|
522
|
+
raw_name = key.cli_option
|
|
523
|
+
next unless raw_name && @explicit_keys.include?(raw_name) && @options.key?(raw_name)
|
|
524
|
+
|
|
525
|
+
options[key.name] = if raw_name == :line_convert
|
|
526
|
+
convert_line_mapping
|
|
527
|
+
else
|
|
528
|
+
convert(raw_name, @options.fetch(raw_name))
|
|
529
|
+
end
|
|
530
|
+
end
|
|
531
|
+
line_mapping = Registry.fetch("source.line_mapping")
|
|
532
|
+
if !options.key?(line_mapping.name) && @explicit_keys.include?(:line_convert_all) &&
|
|
533
|
+
@options.key?(:line_convert_all)
|
|
534
|
+
options[line_mapping.name] = convert_line_mapping
|
|
535
|
+
end
|
|
536
|
+
options
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
private
|
|
540
|
+
|
|
541
|
+
# @rbs (Symbol name, untyped value) -> config_value
|
|
542
|
+
def convert(name, value)
|
|
543
|
+
case name
|
|
544
|
+
when :entry_isolation then convert_entry_isolation(value)
|
|
545
|
+
when :cst_trivia then value == :attach ? :leading : value
|
|
546
|
+
else value
|
|
547
|
+
end
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
# @rbs (untyped value) -> config_value
|
|
551
|
+
def convert_entry_isolation(value)
|
|
552
|
+
return :isolated if value == true
|
|
553
|
+
return :shared if value == false
|
|
554
|
+
|
|
555
|
+
value
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
# @rbs () -> Symbol
|
|
559
|
+
def convert_line_mapping
|
|
560
|
+
line_convert = @options.fetch(:line_convert, true)
|
|
561
|
+
line_convert_all = @options.fetch(:line_convert_all, false)
|
|
562
|
+
unless BOOLEAN_VALUES.include?(line_convert)
|
|
563
|
+
raise ArgumentError, "line_convert expects boolean, got #{line_convert.inspect}"
|
|
564
|
+
end
|
|
565
|
+
unless BOOLEAN_VALUES.include?(line_convert_all)
|
|
566
|
+
raise ArgumentError, "line_convert_all expects boolean, got #{line_convert_all.inspect}"
|
|
567
|
+
end
|
|
568
|
+
if line_convert_all && !line_convert
|
|
569
|
+
raise ArgumentError, "line_convert_all=true conflicts with line_convert=false"
|
|
570
|
+
end
|
|
571
|
+
return :all if line_convert_all
|
|
572
|
+
return :none unless line_convert
|
|
573
|
+
|
|
574
|
+
:actions
|
|
575
|
+
end
|
|
576
|
+
end
|
|
577
|
+
end
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
require_relative "configuration/explanation"
|
|
@@ -5,6 +5,9 @@ module Ibex
|
|
|
5
5
|
module Coverage
|
|
6
6
|
# Strictly turns one or more complete parse sessions into a coverage report.
|
|
7
7
|
class Collector
|
|
8
|
+
# @rbs!
|
|
9
|
+
# type json_value = String | Integer | Float | bool | nil | Array[json_value] | Hash[String, json_value]
|
|
10
|
+
|
|
8
11
|
# @rbs @grammar_digest: String?
|
|
9
12
|
# @rbs @table_format_version: Integer?
|
|
10
13
|
# @rbs @state_count: Integer?
|
|
@@ -39,14 +42,19 @@ module Ibex
|
|
|
39
42
|
collector.finish(source: path)
|
|
40
43
|
end
|
|
41
44
|
|
|
42
|
-
# @rbs (Hash[String,
|
|
45
|
+
# @rbs (Hash[String, json_value] document, source: String, line: Integer) -> void
|
|
43
46
|
def consume(document, source:, line:)
|
|
44
47
|
event = document.fetch("event")
|
|
45
48
|
sequence = document.fetch("sequence")
|
|
49
|
+
data = document.fetch("data")
|
|
50
|
+
unless event.is_a?(String) && data.is_a?(Hash) && data.keys.all?(String)
|
|
51
|
+
invalid(source, line, "event document contains invalid session data")
|
|
52
|
+
end
|
|
53
|
+
event_data = data #: Hash[String, json_value]
|
|
46
54
|
if event == "start"
|
|
47
|
-
start_session(
|
|
55
|
+
start_session(event_data, sequence, source, line)
|
|
48
56
|
else
|
|
49
|
-
consume_session_event(event,
|
|
57
|
+
consume_session_event(event, event_data, sequence, source, line)
|
|
50
58
|
end
|
|
51
59
|
@event_count += 1
|
|
52
60
|
end
|
|
@@ -71,7 +79,7 @@ module Ibex
|
|
|
71
79
|
|
|
72
80
|
private
|
|
73
81
|
|
|
74
|
-
# @rbs (Hash[
|
|
82
|
+
# @rbs (Hash[String, json_value] data, json_value sequence, String source, Integer line) -> void
|
|
75
83
|
def start_session(data, sequence, source, line)
|
|
76
84
|
invalid(source, line, "new start event before prior session ended") if @in_session
|
|
77
85
|
invalid(source, line, "start event sequence must be 1") unless sequence == 1
|
|
@@ -85,7 +93,7 @@ module Ibex
|
|
|
85
93
|
@expected_sequence = 2
|
|
86
94
|
end
|
|
87
95
|
|
|
88
|
-
# @rbs (String event, Hash[
|
|
96
|
+
# @rbs (String event, Hash[String, json_value] data, json_value sequence, String source, Integer line) -> void
|
|
89
97
|
def consume_session_event(event, data, sequence, source, line)
|
|
90
98
|
invalid(source, line, "event appears outside a parse session") unless @in_session
|
|
91
99
|
unless sequence == @expected_sequence
|
|
@@ -106,7 +114,7 @@ module Ibex
|
|
|
106
114
|
end
|
|
107
115
|
end
|
|
108
116
|
|
|
109
|
-
# @rbs (Hash[
|
|
117
|
+
# @rbs (Hash[String, json_value] data, String source, Integer line)
|
|
110
118
|
# -> [[String, Integer, Integer, Integer], Integer]
|
|
111
119
|
def session_metadata(data, source, line)
|
|
112
120
|
digest = data["grammar_digest"]
|
|
@@ -148,21 +156,23 @@ module Ibex
|
|
|
148
156
|
invalid(source, line, e.message)
|
|
149
157
|
end
|
|
150
158
|
|
|
151
|
-
# @rbs (
|
|
159
|
+
# @rbs (json_value id, String source, Integer line) -> void
|
|
152
160
|
def hit_state(id, source, line)
|
|
153
161
|
total = required_metadata(@state_count)
|
|
154
162
|
invalid(source, line, "state id #{id.inspect} is outside 0...#{total}") unless valid_id?(id, total)
|
|
155
|
-
|
|
163
|
+
state_id = id #: Integer
|
|
164
|
+
increment(@state_hits, state_id, "state", source, line)
|
|
156
165
|
end
|
|
157
166
|
|
|
158
|
-
# @rbs (
|
|
167
|
+
# @rbs (json_value id, String source, Integer line) -> void
|
|
159
168
|
def hit_production(id, source, line)
|
|
160
169
|
total = required_metadata(@production_count)
|
|
161
170
|
invalid(source, line, "production id #{id.inspect} is outside 0...#{total}") unless valid_id?(id, total)
|
|
162
|
-
|
|
171
|
+
production_id = id #: Integer
|
|
172
|
+
increment(@production_hits, production_id, "production", source, line)
|
|
163
173
|
end
|
|
164
174
|
|
|
165
|
-
# @rbs (
|
|
175
|
+
# @rbs (json_value id, Integer total) -> bool
|
|
166
176
|
def valid_id?(id, total)
|
|
167
177
|
id.is_a?(Integer) && id >= 0 && id < total
|
|
168
178
|
end
|