ibex 0.2.0 → 0.4.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 +100 -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 +274 -0
- data/docs/development.md +196 -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 +1617 -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/impact.md +101 -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 +129 -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 +310 -0
- data/docs/stability.md +145 -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/sets.rb +14 -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/impact.rb +393 -0
- 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 +362 -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 +141 -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/impact/action_impact.rb +148 -0
- data/lib/ibex/impact/automaton_impact.rb +57 -0
- data/lib/ibex/impact/coverage_impact.rb +53 -0
- data/lib/ibex/impact/graph.rb +132 -0
- data/lib/ibex/impact/propagation.rb +147 -0
- data/lib/ibex/impact/report.rb +273 -0
- data/lib/ibex/impact/seeds.rb +69 -0
- data/lib/ibex/impact/severity.rb +139 -0
- data/lib/ibex/impact.rb +16 -0
- 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 +11 -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/impact-v1.schema.json +208 -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/analysis/sets.rbs +10 -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/impact.rbs +95 -0
- 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/impact/action_impact.rbs +58 -0
- data/sig/ibex/impact/automaton_impact.rbs +37 -0
- data/sig/ibex/impact/coverage_impact.rbs +28 -0
- data/sig/ibex/impact/graph.rbs +67 -0
- data/sig/ibex/impact/propagation.rbs +56 -0
- data/sig/ibex/impact/report.rbs +107 -0
- data/sig/ibex/impact/seeds.rbs +36 -0
- data/sig/ibex/impact/severity.rbs +55 -0
- data/sig/ibex/impact.rbs +6 -0
- 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 +254 -12
- data/lib/ibex/ir/migration.rb +0 -120
- data/sig/ibex/ir/migration.rbs +0 -34
|
@@ -10,6 +10,9 @@ module Ibex
|
|
|
10
10
|
module Coverage
|
|
11
11
|
# Bounded reader for the public runtime-event JSON Lines protocol.
|
|
12
12
|
module EventStream
|
|
13
|
+
# @rbs!
|
|
14
|
+
# type json_value = String | Integer | Float | bool | nil | Array[json_value] | Hash[String, json_value]
|
|
15
|
+
|
|
13
16
|
# @rbs!
|
|
14
17
|
# interface _CoverageEventInput
|
|
15
18
|
# def gets: (Integer) -> String?
|
|
@@ -21,13 +24,13 @@ module Ibex
|
|
|
21
24
|
EVENT_TYPES = %w[start shift reduce error recover discard accept reject].freeze #: Array[String]
|
|
22
25
|
|
|
23
26
|
class << self
|
|
24
|
-
# @rbs (String path) { (Hash[String,
|
|
27
|
+
# @rbs (String path) { (Hash[String, json_value], Integer) -> void } -> void
|
|
25
28
|
def each_file(path, &block)
|
|
26
29
|
File.open(path, "rb") { |input| each_io(input, source: path, &block) }
|
|
27
30
|
end
|
|
28
31
|
|
|
29
32
|
# @rbs (_CoverageEventInput input, source: String)
|
|
30
|
-
# { (Hash[String,
|
|
33
|
+
# { (Hash[String, json_value], Integer) -> void } -> void
|
|
31
34
|
def each_io(input, source:, &block)
|
|
32
35
|
line_number = 0
|
|
33
36
|
while (line = input.gets(MAX_LINE_BYTES + 1))
|
|
@@ -49,20 +52,23 @@ module Ibex
|
|
|
49
52
|
raise_invalid(source, line_number, "event line exceeds #{MAX_LINE_BYTES} bytes")
|
|
50
53
|
end
|
|
51
54
|
|
|
52
|
-
# @rbs (String line, String source, Integer line_number) -> Hash[String,
|
|
55
|
+
# @rbs (String line, String source, Integer line_number) -> Hash[String, json_value]
|
|
53
56
|
def parse_line(line, source, line_number)
|
|
54
57
|
text = line.dup.force_encoding(Encoding::UTF_8)
|
|
55
58
|
raise_invalid(source, line_number, "event line is not valid UTF-8") unless text.valid_encoding?
|
|
56
59
|
|
|
57
|
-
value = JSON.parse(text, max_nesting: MAX_NESTING, allow_nan: false)
|
|
58
|
-
|
|
60
|
+
value = JSON.parse(text, max_nesting: MAX_NESTING, allow_nan: false) #: json_value
|
|
61
|
+
if value.is_a?(Hash) && value.keys.all?(String)
|
|
62
|
+
document = value #: Hash[String, json_value]
|
|
63
|
+
return document
|
|
64
|
+
end
|
|
59
65
|
|
|
60
66
|
raise_invalid(source, line_number, "event line must be a JSON object")
|
|
61
67
|
rescue JSON::ParserError => e
|
|
62
68
|
raise_invalid(source, line_number, "invalid event JSON: #{e.message}")
|
|
63
69
|
end
|
|
64
70
|
|
|
65
|
-
# @rbs (Hash[String,
|
|
71
|
+
# @rbs (Hash[String, json_value] document, String source, Integer line_number) -> void
|
|
66
72
|
def validate_envelope(document, source, line_number)
|
|
67
73
|
unless document.keys.sort == ROOT_KEYS
|
|
68
74
|
raise_invalid(source, line_number, "event object has unknown or missing fields")
|
|
@@ -82,7 +88,7 @@ module Ibex
|
|
|
82
88
|
raise_invalid(source, line_number, "event data does not match the runtime-event v1 schema")
|
|
83
89
|
end
|
|
84
90
|
|
|
85
|
-
# @rbs (
|
|
91
|
+
# @rbs (json_value value) -> bool
|
|
86
92
|
def positive_integer?(value)
|
|
87
93
|
value.is_a?(Integer) && value.positive?
|
|
88
94
|
end
|
data/lib/ibex/coverage/report.rb
CHANGED
|
@@ -8,6 +8,9 @@ module Ibex
|
|
|
8
8
|
module Coverage
|
|
9
9
|
# Versioned, mergeable runtime coverage result.
|
|
10
10
|
class Report
|
|
11
|
+
# @rbs!
|
|
12
|
+
# type json_value = String | Integer | Float | bool | nil | Array[json_value] | Hash[String, json_value]
|
|
13
|
+
|
|
11
14
|
IDENTIFIER = "runtime-coverage" #: String
|
|
12
15
|
SCHEMA_VERSION = 1 #: Integer
|
|
13
16
|
MAX_DOCUMENT_BYTES = 16_777_216 #: Integer
|
|
@@ -46,7 +49,7 @@ module Ibex
|
|
|
46
49
|
end
|
|
47
50
|
# rubocop:enable Layout/LineLength
|
|
48
51
|
|
|
49
|
-
# @rbs () -> Hash[String,
|
|
52
|
+
# @rbs () -> Hash[String, json_value]
|
|
50
53
|
def to_h
|
|
51
54
|
{
|
|
52
55
|
"ibex_coverage" => IDENTIFIER,
|
|
@@ -61,7 +64,7 @@ module Ibex
|
|
|
61
64
|
}
|
|
62
65
|
end
|
|
63
66
|
|
|
64
|
-
# @rbs (*
|
|
67
|
+
# @rbs (*Object) -> String
|
|
65
68
|
def to_json(*)
|
|
66
69
|
"#{JSON.pretty_generate(to_h)}\n"
|
|
67
70
|
end
|
|
@@ -87,7 +90,7 @@ module Ibex
|
|
|
87
90
|
raise Ibex::Error, "#{path}:1:1: invalid coverage JSON: #{e.message}"
|
|
88
91
|
end
|
|
89
92
|
|
|
90
|
-
# @rbs (
|
|
93
|
+
# @rbs (json_value value, source: String) -> Report
|
|
91
94
|
def self.from_h(value, source:)
|
|
92
95
|
document = string_hash(value, source, "coverage document")
|
|
93
96
|
invalid(source, "coverage object has unknown or missing fields") unless document.keys.sort == ROOT_KEYS
|
|
@@ -97,15 +100,19 @@ module Ibex
|
|
|
97
100
|
totals = string_hash(document["totals"], source, "coverage totals")
|
|
98
101
|
invalid(source, "coverage totals have unknown or missing fields") unless totals.keys.sort == TOTAL_KEYS
|
|
99
102
|
|
|
100
|
-
|
|
101
|
-
|
|
103
|
+
grammar_digest = document["grammar_digest"] #: String
|
|
104
|
+
table_format_version = document["table_format_version"] #: Integer
|
|
105
|
+
state_count = totals["states"] #: Integer
|
|
106
|
+
production_count = totals["productions"] #: Integer
|
|
107
|
+
sessions = document["sessions"] #: Integer
|
|
108
|
+
event_count = document["events"] #: Integer
|
|
102
109
|
new(
|
|
103
|
-
grammar_digest:
|
|
104
|
-
table_format_version:
|
|
110
|
+
grammar_digest: grammar_digest,
|
|
111
|
+
table_format_version: table_format_version,
|
|
105
112
|
state_count: state_count,
|
|
106
113
|
production_count: production_count,
|
|
107
|
-
sessions:
|
|
108
|
-
event_count:
|
|
114
|
+
sessions: sessions,
|
|
115
|
+
event_count: event_count,
|
|
109
116
|
state_hits: parse_hits(document["state_hits"], state_count, source, "state"),
|
|
110
117
|
production_hits: parse_hits(document["production_hits"], production_count, source, "production")
|
|
111
118
|
)
|
|
@@ -133,22 +140,21 @@ module Ibex
|
|
|
133
140
|
|
|
134
141
|
private
|
|
135
142
|
|
|
136
|
-
# @rbs (
|
|
143
|
+
# @rbs (json_value input) -> String
|
|
137
144
|
def validate_digest(input)
|
|
138
|
-
|
|
139
|
-
return input.dup.freeze if valid
|
|
145
|
+
return input.dup.freeze if input.is_a?(String) && input.match?(/\Asha256:[0-9a-f]{64}\z/)
|
|
140
146
|
|
|
141
147
|
raise ArgumentError, "grammar_digest must be a full lowercase SHA-256 digest"
|
|
142
148
|
end
|
|
143
149
|
|
|
144
|
-
# @rbs (
|
|
150
|
+
# @rbs (json_value input, String name) -> Integer
|
|
145
151
|
def positive_integer(input, name)
|
|
146
152
|
return input if input.is_a?(Integer) && input.positive? && input <= MAX_COUNT
|
|
147
153
|
|
|
148
154
|
raise ArgumentError, "#{name} must be a bounded positive integer"
|
|
149
155
|
end
|
|
150
156
|
|
|
151
|
-
# @rbs (
|
|
157
|
+
# @rbs (json_value input, String name, minimum: Integer) -> Integer
|
|
152
158
|
def total_integer(input, name, minimum:)
|
|
153
159
|
return input if input.is_a?(Integer) && input >= minimum && input <= MAX_TOTAL
|
|
154
160
|
|
|
@@ -182,14 +188,16 @@ module Ibex
|
|
|
182
188
|
class << self
|
|
183
189
|
private
|
|
184
190
|
|
|
185
|
-
# @rbs (
|
|
191
|
+
# @rbs (json_value value, String source, String name) -> Hash[String, json_value]
|
|
186
192
|
def string_hash(value, source, name)
|
|
187
|
-
|
|
193
|
+
if value.is_a?(Hash) && value.keys.all?(String)
|
|
194
|
+
return value #: Hash[String, json_value]
|
|
195
|
+
end
|
|
188
196
|
|
|
189
197
|
invalid(source, "#{name} must be an object")
|
|
190
198
|
end
|
|
191
199
|
|
|
192
|
-
# @rbs (
|
|
200
|
+
# @rbs (json_value value, json_value total, String source, String kind) -> Hash[Integer, Integer]
|
|
193
201
|
def parse_hits(value, total, source, kind)
|
|
194
202
|
invalid(source, "#{kind}_hits must be an array") unless value.is_a?(Array)
|
|
195
203
|
hits = {} #: Hash[Integer, Integer]
|
|
@@ -202,7 +210,7 @@ module Ibex
|
|
|
202
210
|
hits
|
|
203
211
|
end
|
|
204
212
|
|
|
205
|
-
# @rbs (
|
|
213
|
+
# @rbs (json_value entry, json_value total, Integer previous, String source, String kind) -> [Integer, Integer]
|
|
206
214
|
def parse_hit(entry, total, previous, source, kind)
|
|
207
215
|
hit = string_hash(entry, source, "#{kind} hit")
|
|
208
216
|
invalid(source, "#{kind} hit has unknown or missing fields") unless hit.keys.sort == HIT_KEYS
|
|
@@ -5,6 +5,9 @@ module Ibex
|
|
|
5
5
|
module Coverage
|
|
6
6
|
# Dependency-free structural validation for runtime-event schema version 1.
|
|
7
7
|
module RuntimeEventValidator
|
|
8
|
+
# @rbs!
|
|
9
|
+
# type json_value = String | Integer | Float | bool | nil | Array[json_value] | Hash[String, json_value]
|
|
10
|
+
|
|
8
11
|
TOKEN_KEYS = %w[location state token token_id value].freeze #: Array[String]
|
|
9
12
|
LOCATION_KEYS = %w[column end_column end_line file line].freeze #: Array[String]
|
|
10
13
|
VALIDATORS = {
|
|
@@ -19,18 +22,23 @@ module Ibex
|
|
|
19
22
|
}.freeze #: Hash[String, Symbol]
|
|
20
23
|
|
|
21
24
|
class << self
|
|
22
|
-
# @rbs (Hash[String,
|
|
25
|
+
# @rbs (Hash[String, json_value] document) -> bool
|
|
23
26
|
def valid?(document)
|
|
24
27
|
data = document["data"]
|
|
25
28
|
return false unless data.is_a?(Hash) && data.keys.all?(String)
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
event_data = data #: Hash[String, json_value]
|
|
31
|
+
|
|
32
|
+
event = document["event"]
|
|
33
|
+
return false unless event.is_a?(String)
|
|
34
|
+
|
|
35
|
+
validator = VALIDATORS[event]
|
|
36
|
+
validator ? send(validator, event_data) : false
|
|
29
37
|
end
|
|
30
38
|
|
|
31
39
|
private
|
|
32
40
|
|
|
33
|
-
# @rbs (Hash[String,
|
|
41
|
+
# @rbs (Hash[String, json_value] data) -> bool
|
|
34
42
|
def valid_start?(data)
|
|
35
43
|
return false unless exact_keys?(
|
|
36
44
|
data,
|
|
@@ -45,45 +53,46 @@ module Ibex
|
|
|
45
53
|
optional_string?(data["grammar_digest"])
|
|
46
54
|
end
|
|
47
55
|
|
|
48
|
-
# @rbs (Hash[String,
|
|
56
|
+
# @rbs (Hash[String, json_value] data) -> bool
|
|
49
57
|
def valid_shift?(data)
|
|
50
58
|
exact_keys?(data, TOKEN_KEYS + %w[from_state]) &&
|
|
51
59
|
valid_token_fields?(data) &&
|
|
52
60
|
integer?(data["from_state"])
|
|
53
61
|
end
|
|
54
62
|
|
|
55
|
-
# @rbs (Hash[String,
|
|
63
|
+
# @rbs (Hash[String, json_value] data) -> bool
|
|
56
64
|
def valid_reduce?(data)
|
|
57
65
|
keys = %w[goto_state lhs location post_state pre_state production_id result rhs_length]
|
|
66
|
+
rhs_length = data["rhs_length"]
|
|
58
67
|
exact_keys?(data, keys) &&
|
|
59
68
|
%w[goto_state lhs post_state pre_state production_id].all? { |key| integer?(data[key]) } &&
|
|
60
|
-
|
|
69
|
+
rhs_length.is_a?(Integer) && rhs_length >= 0 &&
|
|
61
70
|
summary?(data["result"]) && location?(data["location"])
|
|
62
71
|
end
|
|
63
72
|
|
|
64
|
-
# @rbs (Hash[String,
|
|
73
|
+
# @rbs (Hash[String, json_value] data, reasons: Array[String]) -> bool
|
|
65
74
|
def valid_token_event?(data, reasons:)
|
|
66
75
|
exact_keys?(data, TOKEN_KEYS + %w[reason]) &&
|
|
67
76
|
valid_token_fields?(data) &&
|
|
68
77
|
reasons.include?(data["reason"])
|
|
69
78
|
end
|
|
70
79
|
|
|
71
|
-
# @rbs (Hash[String,
|
|
80
|
+
# @rbs (Hash[String, json_value] data) -> bool
|
|
72
81
|
def valid_error?(data)
|
|
73
82
|
valid_token_event?(data, reasons: %w[syntax semantic])
|
|
74
83
|
end
|
|
75
84
|
|
|
76
|
-
# @rbs (Hash[String,
|
|
85
|
+
# @rbs (Hash[String, json_value] data) -> bool
|
|
77
86
|
def valid_discard?(data)
|
|
78
87
|
valid_token_event?(data, reasons: %w[recovery])
|
|
79
88
|
end
|
|
80
89
|
|
|
81
|
-
# @rbs (Hash[String,
|
|
90
|
+
# @rbs (Hash[String, json_value] data) -> bool
|
|
82
91
|
def valid_reject?(data)
|
|
83
92
|
valid_token_event?(data, reasons: %w[eof_during_recovery no_recovery_state])
|
|
84
93
|
end
|
|
85
94
|
|
|
86
|
-
# @rbs (Hash[String,
|
|
95
|
+
# @rbs (Hash[String, json_value] data) -> bool
|
|
87
96
|
def valid_recover?(data)
|
|
88
97
|
exact_keys?(data, TOKEN_KEYS + %w[from_state reason]) &&
|
|
89
98
|
valid_token_fields?(data) &&
|
|
@@ -91,7 +100,7 @@ module Ibex
|
|
|
91
100
|
%w[syntax semantic].include?(data["reason"])
|
|
92
101
|
end
|
|
93
102
|
|
|
94
|
-
# @rbs (Hash[String,
|
|
103
|
+
# @rbs (Hash[String, json_value] data) -> bool
|
|
95
104
|
def valid_accept?(data)
|
|
96
105
|
exact_keys?(data, %w[reason result state]) &&
|
|
97
106
|
integer?(data["state"]) &&
|
|
@@ -99,7 +108,7 @@ module Ibex
|
|
|
99
108
|
%w[table semantic].include?(data["reason"])
|
|
100
109
|
end
|
|
101
110
|
|
|
102
|
-
# @rbs (Hash[String,
|
|
111
|
+
# @rbs (Hash[String, json_value] data) -> bool
|
|
103
112
|
def valid_token_fields?(data)
|
|
104
113
|
integer?(data["state"]) &&
|
|
105
114
|
optional_integer?(data["token_id"]) &&
|
|
@@ -108,7 +117,7 @@ module Ibex
|
|
|
108
117
|
location?(data["location"])
|
|
109
118
|
end
|
|
110
119
|
|
|
111
|
-
# @rbs (
|
|
120
|
+
# @rbs (json_value value) -> bool
|
|
112
121
|
def summary?(value)
|
|
113
122
|
case value
|
|
114
123
|
when nil, true, false, Integer then true
|
|
@@ -118,7 +127,7 @@ module Ibex
|
|
|
118
127
|
end
|
|
119
128
|
end
|
|
120
129
|
|
|
121
|
-
# @rbs (
|
|
130
|
+
# @rbs (json_value value) -> bool
|
|
122
131
|
def composite_summary?(value)
|
|
123
132
|
return value.length <= 17 && value.all? { |entry| summary?(entry) } if value.is_a?(Array)
|
|
124
133
|
return false unless value.is_a?(Hash)
|
|
@@ -126,7 +135,7 @@ module Ibex
|
|
|
126
135
|
value.keys.all?(String) && value.length <= 17 && value.values.all? { |entry| summary?(entry) }
|
|
127
136
|
end
|
|
128
137
|
|
|
129
|
-
# @rbs (
|
|
138
|
+
# @rbs (json_value value) -> bool
|
|
130
139
|
def location?(value)
|
|
131
140
|
return true if value.nil?
|
|
132
141
|
return false unless value.is_a?(Hash) && value.keys.all?(String)
|
|
@@ -135,22 +144,22 @@ module Ibex
|
|
|
135
144
|
(value.keys - LOCATION_KEYS).empty? && value.values.all? { |entry| summary?(entry) }
|
|
136
145
|
end
|
|
137
146
|
|
|
138
|
-
# @rbs (Hash[String,
|
|
147
|
+
# @rbs (Hash[String, json_value] data, Array[String] keys) -> bool
|
|
139
148
|
def exact_keys?(data, keys)
|
|
140
149
|
data.keys.sort == keys.sort
|
|
141
150
|
end
|
|
142
151
|
|
|
143
|
-
# @rbs (
|
|
152
|
+
# @rbs (json_value value) -> bool
|
|
144
153
|
def integer?(value)
|
|
145
154
|
value.is_a?(Integer)
|
|
146
155
|
end
|
|
147
156
|
|
|
148
|
-
# @rbs (
|
|
157
|
+
# @rbs (json_value value) -> bool
|
|
149
158
|
def optional_integer?(value)
|
|
150
159
|
value.nil? || integer?(value)
|
|
151
160
|
end
|
|
152
161
|
|
|
153
|
-
# @rbs (
|
|
162
|
+
# @rbs (json_value value) -> bool
|
|
154
163
|
def optional_string?(value)
|
|
155
164
|
value.nil? || value.is_a?(String)
|
|
156
165
|
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
module Ibex
|
|
5
|
+
# Deterministic, trial-bounded delta debugging over an ordered sequence.
|
|
6
|
+
class DeltaReducer
|
|
7
|
+
# Immutable outcome of a bounded reduction.
|
|
8
|
+
class Result
|
|
9
|
+
attr_reader :items #: Array[untyped]
|
|
10
|
+
attr_reader :trials #: Integer
|
|
11
|
+
attr_reader :complete #: bool
|
|
12
|
+
attr_reader :original_size #: Integer
|
|
13
|
+
|
|
14
|
+
# @rbs (items: Array[untyped], trials: Integer, complete: bool, original_size: Integer) -> void
|
|
15
|
+
def initialize(items:, trials:, complete:, original_size:)
|
|
16
|
+
@items = items.freeze
|
|
17
|
+
@trials = trials
|
|
18
|
+
@complete = complete
|
|
19
|
+
@original_size = original_size
|
|
20
|
+
freeze
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @rbs (?max_trials: Integer) -> void
|
|
25
|
+
def initialize(max_trials: 1_000)
|
|
26
|
+
raise ArgumentError, "max_trials must be positive" unless max_trials.positive?
|
|
27
|
+
|
|
28
|
+
@max_trials = max_trials
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# `failure` must return true while the failure of interest is preserved.
|
|
32
|
+
# @rbs [T] (Array[T] items) { (Array[T]) -> bool } -> Result
|
|
33
|
+
def minimize(items, &failure)
|
|
34
|
+
raise ArgumentError, "a failure predicate is required" unless failure
|
|
35
|
+
|
|
36
|
+
current = items.dup
|
|
37
|
+
original_size = current.length
|
|
38
|
+
trials = 0
|
|
39
|
+
trials = checked_trial!(trials)
|
|
40
|
+
unless failure.call(current.freeze)
|
|
41
|
+
raise Ibex::Error, "(reduce):1:1: original input does not reproduce the failure"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
granularity = 2
|
|
45
|
+
while current.length >= 1
|
|
46
|
+
chunks = partitions(current.length, granularity)
|
|
47
|
+
reduced = false
|
|
48
|
+
chunks.each do |range|
|
|
49
|
+
return result(current, trials, false, original_size) if trials >= @max_trials
|
|
50
|
+
|
|
51
|
+
candidate = current.dup
|
|
52
|
+
candidate.slice!(range)
|
|
53
|
+
trials = checked_trial!(trials)
|
|
54
|
+
next unless failure.call(candidate.freeze)
|
|
55
|
+
|
|
56
|
+
current = candidate
|
|
57
|
+
granularity = [granularity - 1, 2].max
|
|
58
|
+
reduced = true
|
|
59
|
+
break
|
|
60
|
+
end
|
|
61
|
+
next if reduced
|
|
62
|
+
break if granularity >= current.length
|
|
63
|
+
|
|
64
|
+
granularity = [granularity * 2, current.length].min
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
result(current, trials, true, original_size)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
# @rbs (Integer length, Integer count) -> Array[Range[Integer]]
|
|
73
|
+
def partitions(length, count)
|
|
74
|
+
width = (length.to_f / count).ceil
|
|
75
|
+
ranges = [] #: Array[Range[Integer]]
|
|
76
|
+
count.times do |index|
|
|
77
|
+
start = index * width
|
|
78
|
+
break if start >= length
|
|
79
|
+
|
|
80
|
+
ranges << (start...[start + width, length].min)
|
|
81
|
+
end
|
|
82
|
+
ranges
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# @rbs (Integer trials) -> Integer
|
|
86
|
+
def checked_trial!(trials)
|
|
87
|
+
raise Ibex::Error, "(reduce):1:1: trial limit of #{@max_trials} is exhausted" if trials >= @max_trials
|
|
88
|
+
|
|
89
|
+
trials + 1
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @rbs (Array[untyped] items, Integer trials, bool complete, Integer original_size) -> Result
|
|
93
|
+
def result(items, trials, complete, original_size)
|
|
94
|
+
Result.new(
|
|
95
|
+
items: items.dup.freeze, trials: trials, complete: complete, original_size: original_size
|
|
96
|
+
).freeze
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
data/lib/ibex/diff.rb
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
module Ibex
|
|
5
|
+
# Deterministic grammar and automaton change classification.
|
|
6
|
+
class Diff
|
|
7
|
+
# @rbs (IR::Automaton before, IR::Automaton after) -> void
|
|
8
|
+
def initialize(before, after)
|
|
9
|
+
@before = before
|
|
10
|
+
@after = after
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @rbs () -> Hash[Symbol, Object?]
|
|
14
|
+
def to_h
|
|
15
|
+
{
|
|
16
|
+
ibex_report: "diff", schema_version: 1,
|
|
17
|
+
symbols: classify(symbol_records(@before.grammar), symbol_records(@after.grammar)),
|
|
18
|
+
rules: classify(rule_records(@before.grammar), rule_records(@after.grammar)),
|
|
19
|
+
conflicts: classify(conflict_records(@before), conflict_records(@after)),
|
|
20
|
+
warnings: classify(warning_records(@before.grammar), warning_records(@after.grammar)),
|
|
21
|
+
metrics: numeric_metrics
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
# @rbs (Hash[String, Object?] before, Hash[String, Object?] after) -> Hash[Symbol, Object?]
|
|
28
|
+
def classify(before, after)
|
|
29
|
+
common = before.keys & after.keys
|
|
30
|
+
{
|
|
31
|
+
added: (after.keys - before.keys).sort.map { |key| { id: key, value: after.fetch(key) } },
|
|
32
|
+
removed: (before.keys - after.keys).sort.map { |key| { id: key, value: before.fetch(key) } },
|
|
33
|
+
changed: common.sort.filter_map do |key|
|
|
34
|
+
next if before.fetch(key) == after.fetch(key)
|
|
35
|
+
|
|
36
|
+
{ id: key, before: before.fetch(key), after: after.fetch(key) }
|
|
37
|
+
end
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @rbs (IR::Grammar grammar) -> Hash[String, Object?]
|
|
42
|
+
def symbol_records(grammar)
|
|
43
|
+
grammar.symbols.to_h do |symbol|
|
|
44
|
+
[
|
|
45
|
+
symbol.name,
|
|
46
|
+
{
|
|
47
|
+
kind: symbol.kind, reserved: symbol.reserved, display_name: symbol.display_name,
|
|
48
|
+
semantic_type: symbol.semantic_type, precedence: symbol.precedence,
|
|
49
|
+
documentation: symbol.documentation
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @rbs (IR::Grammar grammar) -> Hash[String, Object?]
|
|
56
|
+
def rule_records(grammar)
|
|
57
|
+
grammar.productions.group_by(&:lhs).to_h do |lhs, productions|
|
|
58
|
+
name = grammar.symbol_by_id(lhs)&.name || lhs.to_s
|
|
59
|
+
alternatives = productions.map { |production| production_record(grammar, production) }
|
|
60
|
+
[name, alternatives]
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @rbs (IR::Grammar grammar, IR::Production production) -> Hash[Symbol, Object?]
|
|
65
|
+
def production_record(grammar, production)
|
|
66
|
+
precedence = production.precedence_override
|
|
67
|
+
{
|
|
68
|
+
rhs: production.rhs.map { |id| symbol_name(grammar, id) },
|
|
69
|
+
precedence: precedence && symbol_name(grammar, precedence),
|
|
70
|
+
node: production.node && {
|
|
71
|
+
name: production.node.fetch(:name), fields: production.node.fetch(:fields)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @rbs (IR::Automaton automaton) -> Hash[String, Object?]
|
|
77
|
+
def conflict_records(automaton)
|
|
78
|
+
grouped = Hash.new { |hash, key| hash[key] = [] } #: Hash[String, Array[Object?]]
|
|
79
|
+
automaton.states.each do |state|
|
|
80
|
+
state.conflicts.each do |conflict|
|
|
81
|
+
identity = conflict_identity(automaton.grammar, conflict)
|
|
82
|
+
grouped[identity] << conflict.fetch(:resolution)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
grouped.transform_values { |resolutions| resolutions.sort_by(&:inspect) }
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# @rbs (IR::Grammar grammar, IR::conflict conflict) -> String
|
|
89
|
+
def conflict_identity(grammar, conflict)
|
|
90
|
+
if conflict.fetch(:type).to_sym == :shift_reduce
|
|
91
|
+
shift_reduce = conflict #: IR::shift_reduce_conflict
|
|
92
|
+
reduction = production_shape(grammar, shift_reduce.fetch(:reduce))
|
|
93
|
+
"shift_reduce:#{shift_reduce.fetch(:symbol)}:#{reduction}"
|
|
94
|
+
else
|
|
95
|
+
reduce_reduce = conflict #: IR::reduce_reduce_conflict
|
|
96
|
+
reductions = reduce_reduce.fetch(:reductions).map { |id| production_shape(grammar, id) }.sort
|
|
97
|
+
"reduce_reduce:#{reduce_reduce.fetch(:symbol)}:#{reductions.join('|')}"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# @rbs (IR::Grammar grammar, Integer id) -> String
|
|
102
|
+
def production_shape(grammar, id)
|
|
103
|
+
production = grammar.productions.fetch(id)
|
|
104
|
+
lhs = symbol_name(grammar, production.lhs)
|
|
105
|
+
rhs = production.rhs.map { |symbol| symbol_name(grammar, symbol) }
|
|
106
|
+
"#{lhs}->#{rhs.join(' ')}"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# @rbs (IR::Grammar grammar, Integer id) -> String
|
|
110
|
+
def symbol_name(grammar, id)
|
|
111
|
+
grammar.symbol_by_id(id)&.name || id.to_s
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# @rbs (IR::Grammar grammar) -> Hash[String, Object?]
|
|
115
|
+
def warning_records(grammar)
|
|
116
|
+
grouped = Hash.new { |hash, key| hash[key] = [] } #: Hash[String, Array[Object?]]
|
|
117
|
+
grammar.warnings.each do |warning|
|
|
118
|
+
value = warning.except(:loc)
|
|
119
|
+
identity = [warning.fetch(:type), value.except(:message).inspect].join(":")
|
|
120
|
+
grouped[identity] << value
|
|
121
|
+
end
|
|
122
|
+
grouped.transform_values { |values| values.sort_by(&:inspect) }
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# @rbs () -> Hash[Symbol, Hash[Symbol, Integer]]
|
|
126
|
+
def numeric_metrics
|
|
127
|
+
{
|
|
128
|
+
states: change(@before.states.length, @after.states.length),
|
|
129
|
+
productions: change(@before.grammar.productions.length, @after.grammar.productions.length),
|
|
130
|
+
warnings: change(@before.grammar.warnings.length, @after.grammar.warnings.length),
|
|
131
|
+
shift_reduce: change(@before.conflict_summary.fetch(:sr), @after.conflict_summary.fetch(:sr)),
|
|
132
|
+
reduce_reduce: change(@before.conflict_summary.fetch(:rr), @after.conflict_summary.fetch(:rr))
|
|
133
|
+
}
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# @rbs (Integer before, Integer after) -> Hash[Symbol, Integer]
|
|
137
|
+
def change(before, after)
|
|
138
|
+
{ before: before, after: after, delta: after - before }
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|