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
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
require "json"
|
|
5
|
+
require "optparse"
|
|
6
|
+
require_relative "../diff"
|
|
7
|
+
require_relative "../metrics"
|
|
8
|
+
|
|
9
|
+
module Ibex
|
|
10
|
+
# CLI entry points for deterministic grammar diff and metrics reports.
|
|
11
|
+
module CLIAnalysis
|
|
12
|
+
# @rbs!
|
|
13
|
+
# type analysis_options = Hash[Symbol, untyped]
|
|
14
|
+
# private def normalize_grammar_path: (String) -> IR::Grammar
|
|
15
|
+
# private def set_configuration_option: (Symbol, Object?) -> void
|
|
16
|
+
# private def local_configuration_value: (Hash[Symbol, untyped], String) -> untyped
|
|
17
|
+
# private def set_local_configuration_option: (Hash[Symbol, untyped], Symbol, untyped) -> void
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
# @rbs (Array[String] arguments) -> Integer
|
|
22
|
+
def run_diff_command(arguments)
|
|
23
|
+
settings = analysis_options(arguments, "diff", operands: "OLD NEW")
|
|
24
|
+
if settings[:help]
|
|
25
|
+
@stdout.puts(settings.fetch(:help))
|
|
26
|
+
return 0
|
|
27
|
+
end
|
|
28
|
+
paths = settings.fetch(:paths)
|
|
29
|
+
raise Ibex::Error, "(diff):1:1: diff requires exactly two grammar or IR files" unless paths.length == 2
|
|
30
|
+
|
|
31
|
+
algorithm = settings.fetch(:algorithm)
|
|
32
|
+
before = load_analysis_automaton(paths.fetch(0), algorithm, explicit: algo_set?(settings))
|
|
33
|
+
after = load_analysis_automaton(paths.fetch(1), algorithm, explicit: algo_set?(settings))
|
|
34
|
+
report = Diff.new(before, after).to_h
|
|
35
|
+
write_analysis_report(report, settings.fetch(:format))
|
|
36
|
+
0
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @rbs (Array[String] arguments) -> Integer
|
|
40
|
+
def run_metrics_command(arguments)
|
|
41
|
+
settings = analysis_options(arguments, "metrics", operands: "GRAMMAR")
|
|
42
|
+
if settings[:help]
|
|
43
|
+
@stdout.puts(settings.fetch(:help))
|
|
44
|
+
return 0
|
|
45
|
+
end
|
|
46
|
+
paths = settings.fetch(:paths)
|
|
47
|
+
raise Ibex::Error, "(metrics):1:1: metrics requires exactly one grammar or IR file" unless paths.length == 1
|
|
48
|
+
|
|
49
|
+
automaton = load_analysis_automaton(paths.fetch(0), settings.fetch(:algorithm), explicit: algo_set?(settings))
|
|
50
|
+
report = Metrics.new(automaton).to_h
|
|
51
|
+
write_analysis_report(report, settings.fetch(:format))
|
|
52
|
+
0
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @rbs (Array[String] arguments, String command, operands: String) -> Hash[Symbol, untyped]
|
|
56
|
+
def analysis_options(arguments, command, operands:)
|
|
57
|
+
settings = {
|
|
58
|
+
paths: [], algorithm: Configuration::Registry.fetch("parser.algorithm").default,
|
|
59
|
+
mode: Configuration::Registry.fetch("grammar.mode").default, format: "json", configuration_explicit: []
|
|
60
|
+
} #: Hash[Symbol, untyped]
|
|
61
|
+
parser = OptionParser.new do |options|
|
|
62
|
+
options.banner = "Usage: ibex #{command} [options] #{operands}"
|
|
63
|
+
options.on("--algorithm=NAME", %w[slr lalr ielr lr1], "algorithm for grammar inputs") do |value|
|
|
64
|
+
set_local_configuration_option(settings, :algorithm, value.to_sym)
|
|
65
|
+
end
|
|
66
|
+
options.on("--mode=MODE", %w[default extended], "grammar mode") do |value|
|
|
67
|
+
set_local_configuration_option(settings, :mode, value.to_sym)
|
|
68
|
+
set_configuration_option(:mode, value.to_sym)
|
|
69
|
+
end
|
|
70
|
+
options.on("--format=FORMAT", %w[json text], "json or text") { |value| settings[:format] = value }
|
|
71
|
+
options.on("--help", "show help") { settings[:help] = options.to_s }
|
|
72
|
+
end
|
|
73
|
+
settings[:paths] = parser.parse(arguments)
|
|
74
|
+
settings[:algorithm] = local_configuration_value(settings, "parser.algorithm")
|
|
75
|
+
settings
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @rbs (String path, Symbol algorithm, explicit: bool) -> IR::Automaton
|
|
79
|
+
def load_analysis_automaton(path, algorithm, explicit:)
|
|
80
|
+
source = File.binread(path)
|
|
81
|
+
if source.lstrip.start_with?("{")
|
|
82
|
+
value = IR::Validator.validate(source)
|
|
83
|
+
if value.is_a?(IR::Automaton)
|
|
84
|
+
raise Ibex::Error, "(cli):1:1: --algorithm cannot be combined with Automaton IR analysis input" if explicit
|
|
85
|
+
|
|
86
|
+
return value
|
|
87
|
+
end
|
|
88
|
+
return build_analysis_automaton(value, algorithm, explicit) if value.is_a?(IR::Grammar)
|
|
89
|
+
|
|
90
|
+
raise Ibex::Error, "#{path}:1:1: analysis does not accept Lexer IR"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
build_analysis_automaton(normalize_grammar_path(path), algorithm, explicit)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# @rbs (IR::Grammar grammar, Symbol algorithm, bool algorithm_explicit) -> IR::Automaton
|
|
97
|
+
def build_analysis_automaton(grammar, algorithm, algorithm_explicit)
|
|
98
|
+
explicit_keys = algorithm_explicit ? [:algorithm] : [] #: Array[Symbol]
|
|
99
|
+
active = activate_analysis_grammar(
|
|
100
|
+
grammar, options: { algorithm: algorithm }, explicit_keys: explicit_keys
|
|
101
|
+
)
|
|
102
|
+
LALR::Builder.new(
|
|
103
|
+
active, algorithm: configuration_value("parser.algorithm"),
|
|
104
|
+
entry_isolation: configuration_value("parser.entries") == :isolated
|
|
105
|
+
).build
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# @rbs (Hash[Symbol, untyped] report, String format) -> void
|
|
109
|
+
def write_analysis_report(report, format)
|
|
110
|
+
if format == "json"
|
|
111
|
+
@stdout.puts(JSON.pretty_generate(report))
|
|
112
|
+
elsif report.fetch(:ibex_report) == "metrics"
|
|
113
|
+
@stdout.puts("states=#{report.dig(:automaton, :states)} rules=#{report.dig(:grammar, :rules)} " \
|
|
114
|
+
"alternatives=#{report.dig(:grammar, :alternatives)}")
|
|
115
|
+
else
|
|
116
|
+
%i[symbols rules conflicts warnings].each do |section|
|
|
117
|
+
values = report.fetch(section)
|
|
118
|
+
@stdout.puts("#{section}: +#{values.fetch(:added).length} " \
|
|
119
|
+
"-#{values.fetch(:removed).length} ~#{values.fetch(:changed).length}")
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @rbs (Hash[Symbol, untyped] settings) -> bool
|
|
125
|
+
def algo_set?(settings)
|
|
126
|
+
settings.fetch(:configuration_explicit).include?(:algorithm)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# @rbs!
|
|
130
|
+
# private def activate_analysis_grammar: (IR::Grammar, ?options: Hash[Symbol, untyped],
|
|
131
|
+
# ?explicit_keys: Array[Symbol]) -> IR::Grammar
|
|
132
|
+
# private def configuration_value: (String) -> untyped
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
require "json"
|
|
5
|
+
require "optparse"
|
|
6
|
+
require_relative "../bison_import"
|
|
7
|
+
|
|
8
|
+
module Ibex
|
|
9
|
+
# CLI boundary for analysis-only Bison grammar import.
|
|
10
|
+
module CLIBisonImport
|
|
11
|
+
# @rbs!
|
|
12
|
+
# type bison_import_options = {
|
|
13
|
+
# format: String,
|
|
14
|
+
# max_bytes: Integer,
|
|
15
|
+
# max_tokens: Integer,
|
|
16
|
+
# max_rules: Integer,
|
|
17
|
+
# max_actions: Integer,
|
|
18
|
+
# ?output: String,
|
|
19
|
+
# ?class_name: String,
|
|
20
|
+
# ?help: bool
|
|
21
|
+
# }
|
|
22
|
+
# private def same_file_target?: (String, String) -> bool
|
|
23
|
+
# private def atomic_write_ir: (String, String) -> void
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
# @rbs (Array[String] arguments) -> Integer
|
|
28
|
+
def run_bison_import_command(arguments)
|
|
29
|
+
kind = arguments.shift
|
|
30
|
+
raise Ibex::Error, "(bison-import):1:1: import requires the `bison` format" unless kind == "bison"
|
|
31
|
+
|
|
32
|
+
settings = default_bison_import_options
|
|
33
|
+
parser = bison_import_option_parser(settings)
|
|
34
|
+
paths = parser.parse(arguments)
|
|
35
|
+
if settings[:help]
|
|
36
|
+
@stdout.puts(parser)
|
|
37
|
+
return 0
|
|
38
|
+
end
|
|
39
|
+
raise Ibex::Error, "(bison-import):1:1: import bison requires exactly one source file" unless paths.length == 1
|
|
40
|
+
|
|
41
|
+
path = paths.fetch(0)
|
|
42
|
+
result = build_bison_import(path, settings)
|
|
43
|
+
rendered = settings.fetch(:format) == "json" ? "#{JSON.pretty_generate(result.to_h)}\n" : result.source
|
|
44
|
+
write_bison_import(path, settings[:output], rendered)
|
|
45
|
+
0
|
|
46
|
+
rescue BisonImport::BudgetExceeded => e
|
|
47
|
+
@stdout.puts(JSON.pretty_generate({ ibex_report: "bison_import", schema_version: 1 }.merge(e.details)))
|
|
48
|
+
2
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @rbs () -> bison_import_options
|
|
52
|
+
def default_bison_import_options
|
|
53
|
+
{
|
|
54
|
+
format: "source",
|
|
55
|
+
max_bytes: BisonImport::Importer::DEFAULT_MAX_BYTES,
|
|
56
|
+
max_tokens: BisonImport::Importer::DEFAULT_MAX_TOKENS,
|
|
57
|
+
max_rules: BisonImport::Importer::DEFAULT_MAX_RULES,
|
|
58
|
+
max_actions: BisonImport::Importer::DEFAULT_MAX_ACTIONS
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @rbs (bison_import_options settings) -> OptionParser
|
|
63
|
+
def bison_import_option_parser(settings)
|
|
64
|
+
OptionParser.new do |options|
|
|
65
|
+
options.banner = "Usage: ibex import bison [options] grammar.y"
|
|
66
|
+
options.on("--format=FORMAT", %w[source json], "converted source or JSON report") do |value|
|
|
67
|
+
settings[:format] = value
|
|
68
|
+
end
|
|
69
|
+
options.on("-o FILE", "--output=FILE", "write atomically to FILE") { |value| settings[:output] = value }
|
|
70
|
+
options.on("--class=NAME", "generated analysis grammar class") { |value| settings[:class_name] = value }
|
|
71
|
+
add_bison_import_budgets(options, settings)
|
|
72
|
+
options.on("--help", "show help") { settings[:help] = true }
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @rbs (OptionParser options, bison_import_options settings) -> void
|
|
77
|
+
def add_bison_import_budgets(options, settings)
|
|
78
|
+
{
|
|
79
|
+
"max-bytes" => :max_bytes,
|
|
80
|
+
"max-tokens" => :max_tokens,
|
|
81
|
+
"max-rules" => :max_rules,
|
|
82
|
+
"max-actions" => :max_actions
|
|
83
|
+
}.each do |name, key|
|
|
84
|
+
options.on("--#{name}=N", Integer, "positive import budget") do |value|
|
|
85
|
+
raise OptionParser::InvalidArgument, "--#{name} must be positive" unless value.positive?
|
|
86
|
+
|
|
87
|
+
settings[key] = value
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @rbs (String path, bison_import_options settings) -> BisonImport::Result
|
|
93
|
+
def build_bison_import(path, settings)
|
|
94
|
+
BisonImport::Importer.new(
|
|
95
|
+
File.binread(path),
|
|
96
|
+
file: path,
|
|
97
|
+
class_name: settings[:class_name],
|
|
98
|
+
max_bytes: settings.fetch(:max_bytes),
|
|
99
|
+
max_tokens: settings.fetch(:max_tokens),
|
|
100
|
+
max_rules: settings.fetch(:max_rules),
|
|
101
|
+
max_actions: settings.fetch(:max_actions)
|
|
102
|
+
).run
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# @rbs (String input, String? output, String source) -> void
|
|
106
|
+
def write_bison_import(input, output, source)
|
|
107
|
+
unless output
|
|
108
|
+
@stdout.write(source)
|
|
109
|
+
return
|
|
110
|
+
end
|
|
111
|
+
if same_file_target?(input, output)
|
|
112
|
+
raise Ibex::Error, "(bison-import):1:1: import input and output paths must be distinct"
|
|
113
|
+
end
|
|
114
|
+
if File.symlink?(output) || (File.exist?(output) && File.stat(output).nlink > 1)
|
|
115
|
+
raise Ibex::Error, "(bison-import):1:1: output refuses symlink aliases and files with multiple hard links"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
atomic_write_ir(output, source)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
require "json"
|
|
5
|
+
require "optparse"
|
|
6
|
+
require_relative "../configuration/inspector"
|
|
7
|
+
require_relative "../frontend/source_loader"
|
|
8
|
+
require_relative "../frontend/resolver"
|
|
9
|
+
require_relative "../ir/validator"
|
|
10
|
+
|
|
11
|
+
module Ibex
|
|
12
|
+
# Static effective-configuration reporting for source grammars and Grammar IR.
|
|
13
|
+
module CLIConfig
|
|
14
|
+
# @rbs!
|
|
15
|
+
# type config_options = {
|
|
16
|
+
# format: String,
|
|
17
|
+
# mode: Symbol,
|
|
18
|
+
# configuration_explicit: Array[Symbol],
|
|
19
|
+
# ?from: String,
|
|
20
|
+
# ?algorithm: Symbol,
|
|
21
|
+
# ?entry_isolation: bool,
|
|
22
|
+
# ?cst_trivia: Symbol,
|
|
23
|
+
# ?superclass: String,
|
|
24
|
+
# ?omit_actions: bool,
|
|
25
|
+
# ?help: String
|
|
26
|
+
# }
|
|
27
|
+
# private def input_path: (Array[String]) -> String
|
|
28
|
+
# private def set_local_configuration_option: (Hash[Symbol, Object?], Symbol, Object?) -> void
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# @rbs (Array[String] arguments) -> Integer
|
|
33
|
+
def run_config_command(arguments)
|
|
34
|
+
settings, paths = config_options(arguments)
|
|
35
|
+
if settings[:help]
|
|
36
|
+
@stdout.puts(settings.fetch(:help))
|
|
37
|
+
return 0
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
path = input_path(paths)
|
|
41
|
+
input = load_configuration_input(path, settings)
|
|
42
|
+
cli_values = Configuration::CLIAdapter.new(
|
|
43
|
+
settings, explicit_keys: settings.fetch(:configuration_explicit)
|
|
44
|
+
).configuration_values
|
|
45
|
+
report = Configuration::Report.new(input, cli: cli_values)
|
|
46
|
+
write_configuration_report(report, settings.fetch(:format))
|
|
47
|
+
return 0 if report.success?
|
|
48
|
+
|
|
49
|
+
report.conflicts.each do |conflict|
|
|
50
|
+
@stderr.puts(Messages.translate("cli.error", language: @language, detail: conflict.message))
|
|
51
|
+
end
|
|
52
|
+
1
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @rbs (Array[String] arguments) -> [config_options, Array[String]]
|
|
56
|
+
def config_options(arguments)
|
|
57
|
+
settings = {
|
|
58
|
+
format: "text", mode: Configuration::Registry.fetch("grammar.mode").default,
|
|
59
|
+
configuration_explicit: []
|
|
60
|
+
} #: config_options
|
|
61
|
+
parser = OptionParser.new do |options|
|
|
62
|
+
options.banner = "Usage: ibex config [options] grammarfile"
|
|
63
|
+
add_config_options(options, settings)
|
|
64
|
+
end
|
|
65
|
+
[settings, parser.parse(arguments)]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @rbs (OptionParser options, config_options settings) -> void
|
|
69
|
+
def add_config_options(options, settings)
|
|
70
|
+
options.on("--format=FORMAT", %w[text json], "text or json (default: text)") do |value|
|
|
71
|
+
settings[:format] = value
|
|
72
|
+
end
|
|
73
|
+
options.on("--from=FORMAT", %w[grammar-ir], "read validated Grammar IR JSON") do |value|
|
|
74
|
+
settings[:from] = value
|
|
75
|
+
end
|
|
76
|
+
add_config_contract_options(options, settings)
|
|
77
|
+
options.on("--help", "show help") { settings[:help] = options.to_s }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @rbs (OptionParser options, config_options settings) -> void
|
|
81
|
+
def add_config_contract_options(options, settings)
|
|
82
|
+
options.on("--mode=MODE", %w[default extended], "grammar mode") do |value|
|
|
83
|
+
set_local_configuration_option(settings, :mode, value.to_sym)
|
|
84
|
+
end
|
|
85
|
+
options.on("--algorithm=NAME", %w[slr lalr ielr lr1], "parser construction algorithm") do |value|
|
|
86
|
+
set_local_configuration_option(settings, :algorithm, value.to_sym)
|
|
87
|
+
end
|
|
88
|
+
options.on("--entry-isolation", "build independent state sets for each start symbol") do
|
|
89
|
+
set_local_configuration_option(settings, :entry_isolation, true)
|
|
90
|
+
end
|
|
91
|
+
options.on("--cst-trivia=POLICY", %w[leading balanced drop attach], "CST trivia policy") do |value|
|
|
92
|
+
set_local_configuration_option(settings, :cst_trivia, value.to_sym)
|
|
93
|
+
end
|
|
94
|
+
options.on("--superclass=CLASS", "request a parser superclass") do |value|
|
|
95
|
+
set_local_configuration_option(settings, :superclass, value)
|
|
96
|
+
end
|
|
97
|
+
options.on("--no-omit-actions", "generate implicit action methods") do
|
|
98
|
+
set_local_configuration_option(settings, :omit_actions, false)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# @rbs (String path, config_options settings) -> Configuration::Input
|
|
103
|
+
def load_configuration_input(path, settings)
|
|
104
|
+
return load_grammar_ir_configuration(path) if settings[:from] == "grammar-ir"
|
|
105
|
+
|
|
106
|
+
loader = Frontend::SourceLoader.new(record_reads: true)
|
|
107
|
+
resolver = Frontend::Resolver.new(path, mode: settings.fetch(:mode), loader: loader)
|
|
108
|
+
Configuration::Inspector.from_source(resolver.resolve)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# @rbs (String path) -> Configuration::Input
|
|
112
|
+
def load_grammar_ir_configuration(path)
|
|
113
|
+
value = IR::Validator.validate(File.binread(path))
|
|
114
|
+
raise Ibex::Error, "#{path}:1:1: expected grammar-ir input" unless value.is_a?(IR::Grammar)
|
|
115
|
+
|
|
116
|
+
Configuration::Inspector.from_grammar_ir(value, path: path)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# @rbs (Configuration::Report report, String format) -> void
|
|
120
|
+
def write_configuration_report(report, format)
|
|
121
|
+
if format == "json"
|
|
122
|
+
@stdout.puts(JSON.pretty_generate(report.to_h))
|
|
123
|
+
else
|
|
124
|
+
@stdout.write(report.render_text)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
data/lib/ibex/cli/diagnostics.rb
CHANGED
|
@@ -11,24 +11,23 @@ module Ibex
|
|
|
11
11
|
DEFAULT_MAX_DIAGNOSTICS = 20 #: Integer
|
|
12
12
|
|
|
13
13
|
# @rbs!
|
|
14
|
-
# type diagnostic_settings =
|
|
15
|
-
# format: String,
|
|
16
|
-
# max_diagnostics: Integer,
|
|
17
|
-
# mode: Symbol,
|
|
18
|
-
# ?help: bool
|
|
19
|
-
# }
|
|
14
|
+
# type diagnostic_settings = Hash[Symbol, untyped]
|
|
20
15
|
#
|
|
21
16
|
# private def input_path: (Array[String]) -> String
|
|
17
|
+
# private def local_configuration_value: (Hash[Symbol, Object?], String) -> Object?
|
|
18
|
+
# private def set_local_configuration_option: (Hash[Symbol, Object?], Symbol, Object?) -> void
|
|
22
19
|
|
|
23
20
|
private
|
|
24
21
|
|
|
25
22
|
# @rbs (Array[String] arguments) -> Integer
|
|
26
23
|
def run_diagnose_command(arguments)
|
|
27
24
|
settings = {
|
|
28
|
-
format: "text", max_diagnostics: DEFAULT_MAX_DIAGNOSTICS,
|
|
25
|
+
format: "text", max_diagnostics: DEFAULT_MAX_DIAGNOSTICS,
|
|
26
|
+
mode: Configuration::Registry.fetch("grammar.mode").default, configuration_explicit: []
|
|
29
27
|
} #: diagnostic_settings
|
|
30
28
|
parser = diagnostics_option_parser(settings)
|
|
31
29
|
remaining = parser.parse(arguments)
|
|
30
|
+
settings[:mode] = local_configuration_value(settings, "grammar.mode")
|
|
32
31
|
if settings[:help]
|
|
33
32
|
@stdout.puts(parser)
|
|
34
33
|
return 0
|
|
@@ -78,7 +77,9 @@ module Ibex
|
|
|
78
77
|
options.on("--max-diagnostics=N", "positive diagnostic limit") do |value|
|
|
79
78
|
settings[:max_diagnostics] = positive_diagnostic_limit(value)
|
|
80
79
|
end
|
|
81
|
-
options.on("--mode=MODE", %w[default extended], "grammar mode")
|
|
80
|
+
options.on("--mode=MODE", %w[default extended], "grammar mode") do |value|
|
|
81
|
+
set_local_configuration_option(settings, :mode, value.to_sym)
|
|
82
|
+
end
|
|
82
83
|
options.on("--help", "show help") { settings[:help] = true }
|
|
83
84
|
end
|
|
84
85
|
end
|
|
@@ -98,19 +99,38 @@ module Ibex
|
|
|
98
99
|
if format == "json"
|
|
99
100
|
@stdout.puts(JSON.pretty_generate(diagnostics_document(result)))
|
|
100
101
|
else
|
|
101
|
-
result.diagnostics.each { |diagnostic| @stdout.puts(diagnostic
|
|
102
|
+
result.diagnostics.each { |diagnostic| @stdout.puts(localized_diagnostic_text(diagnostic)) }
|
|
102
103
|
end
|
|
103
104
|
end
|
|
104
105
|
|
|
105
|
-
# @rbs (Frontend::ParseResult result) -> Hash[String,
|
|
106
|
+
# @rbs (Frontend::ParseResult result) -> Hash[String, Object?]
|
|
106
107
|
def diagnostics_document(result)
|
|
107
108
|
{
|
|
108
109
|
"ibex_diagnostics" => "frontend",
|
|
109
110
|
"schema_version" => DIAGNOSTICS_SCHEMA_VERSION,
|
|
110
111
|
"success" => result.success?,
|
|
111
112
|
"ast_available" => !result.ast.nil?,
|
|
112
|
-
"diagnostics" => result.diagnostics.map(
|
|
113
|
+
"diagnostics" => result.diagnostics.map { |diagnostic| localized_diagnostic_hash(diagnostic) }
|
|
113
114
|
}
|
|
114
115
|
end
|
|
116
|
+
|
|
117
|
+
# @rbs (Frontend::Diagnostic diagnostic) -> String
|
|
118
|
+
def localized_diagnostic_text(diagnostic)
|
|
119
|
+
return diagnostic.to_s if @language == "en"
|
|
120
|
+
|
|
121
|
+
"#{diagnostic.location}: #{localized_diagnostic_message(diagnostic)}"
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @rbs (Frontend::Diagnostic diagnostic) -> Hash[Symbol, Object?]
|
|
125
|
+
def localized_diagnostic_hash(diagnostic)
|
|
126
|
+
diagnostic.to_h.merge(message: localized_diagnostic_message(diagnostic))
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# @rbs (Frontend::Diagnostic diagnostic) -> String
|
|
130
|
+
def localized_diagnostic_message(diagnostic)
|
|
131
|
+
id = "diagnostic.#{diagnostic.code}"
|
|
132
|
+
id = "diagnostic.generic" unless Messages.known?(id)
|
|
133
|
+
Messages.translate(id, language: @language, detail: diagnostic.message)
|
|
134
|
+
end
|
|
115
135
|
end
|
|
116
136
|
end
|
|
@@ -9,24 +9,25 @@ module Ibex
|
|
|
9
9
|
# Generates standalone grammar documentation from the canonical include closure.
|
|
10
10
|
module CLIDocumentation
|
|
11
11
|
# @rbs!
|
|
12
|
-
# type documentation_settings =
|
|
13
|
-
# format: String,
|
|
14
|
-
# mode: Symbol,
|
|
15
|
-
# ?output: String,
|
|
16
|
-
# ?help: bool
|
|
17
|
-
# }
|
|
12
|
+
# type documentation_settings = Hash[Symbol, untyped]
|
|
18
13
|
#
|
|
19
14
|
# private def input_path: (Array[String]) -> String
|
|
20
15
|
# private def same_file_target?: (String left, String right) -> bool
|
|
21
16
|
# private def atomic_write_ir: (String path, String source) -> void
|
|
17
|
+
# private def local_configuration_value: (Hash[Symbol, Object?], String) -> Object?
|
|
18
|
+
# private def set_local_configuration_option: (Hash[Symbol, Object?], Symbol, Object?) -> void
|
|
22
19
|
|
|
23
20
|
private
|
|
24
21
|
|
|
25
22
|
# @rbs (Array[String] arguments) -> Integer
|
|
26
23
|
def run_documentation_command(arguments)
|
|
27
|
-
settings = {
|
|
24
|
+
settings = {
|
|
25
|
+
format: "markdown", mode: Configuration::Registry.fetch("grammar.mode").default,
|
|
26
|
+
configuration_explicit: []
|
|
27
|
+
} #: documentation_settings
|
|
28
28
|
parser = documentation_option_parser(settings)
|
|
29
29
|
remaining = parser.parse(arguments)
|
|
30
|
+
settings[:mode] = local_configuration_value(settings, "grammar.mode")
|
|
30
31
|
if settings[:help]
|
|
31
32
|
@stdout.puts(parser)
|
|
32
33
|
return 0
|
|
@@ -59,7 +60,9 @@ module Ibex
|
|
|
59
60
|
settings[:format] = value
|
|
60
61
|
end
|
|
61
62
|
options.on("-o FILE", "--output=FILE", "write atomically to FILE") { |value| settings[:output] = value }
|
|
62
|
-
options.on("--mode=MODE", %w[default extended], "grammar mode")
|
|
63
|
+
options.on("--mode=MODE", %w[default extended], "grammar mode") do |value|
|
|
64
|
+
set_local_configuration_option(settings, :mode, value.to_sym)
|
|
65
|
+
end
|
|
63
66
|
options.on("--help", "show help") { settings[:help] = true }
|
|
64
67
|
end
|
|
65
68
|
end
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
require "json"
|
|
5
|
+
require "optparse"
|
|
6
|
+
require_relative "../equiv"
|
|
7
|
+
|
|
8
|
+
module Ibex
|
|
9
|
+
# CLI entry point for bounded language comparison.
|
|
10
|
+
module CLIEquiv
|
|
11
|
+
# @rbs!
|
|
12
|
+
# type equiv_options = Hash[Symbol, untyped]
|
|
13
|
+
# private def normalize_grammar_path: (String) -> IR::Grammar
|
|
14
|
+
# private def configuration_value: (String) -> untyped
|
|
15
|
+
# private def set_configuration_option: (Symbol, Object?) -> void
|
|
16
|
+
# private def local_configuration_value: (Hash[Symbol, Object?], String) -> Object?
|
|
17
|
+
# private def set_local_configuration_option: (Hash[Symbol, Object?], Symbol, Object?) -> void
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
# @rbs (Array[String] arguments) -> Integer
|
|
22
|
+
def run_equiv_command(arguments)
|
|
23
|
+
settings = equiv_options(arguments)
|
|
24
|
+
if settings[:help]
|
|
25
|
+
@stdout.puts(settings.fetch(:help))
|
|
26
|
+
return 0
|
|
27
|
+
end
|
|
28
|
+
paths = settings.fetch(:paths)
|
|
29
|
+
raise Ibex::Error, "(equiv):1:1: equiv requires exactly two grammar or IR files" unless paths.length == 2
|
|
30
|
+
|
|
31
|
+
algorithm = settings.fetch(:algorithm)
|
|
32
|
+
left = load_equiv_automaton(paths.fetch(0), algorithm, explicit: algorithm_explicit_equiv?(settings))
|
|
33
|
+
right = load_equiv_automaton(paths.fetch(1), algorithm, explicit: algorithm_explicit_equiv?(settings))
|
|
34
|
+
comparison = Equiv.new(
|
|
35
|
+
left, right,
|
|
36
|
+
sample_count: settings.fetch(:sample_count), seed: settings.fetch(:seed),
|
|
37
|
+
max_tokens: settings.fetch(:max_tokens), max_configurations: settings.fetch(:max_configurations),
|
|
38
|
+
max_actions: settings.fetch(:max_actions), max_stack: settings.fetch(:max_stack),
|
|
39
|
+
rule_map: settings.fetch(:rule_map)
|
|
40
|
+
)
|
|
41
|
+
write_equiv_report(comparison.run, settings.fetch(:format))
|
|
42
|
+
0
|
|
43
|
+
rescue Equiv::Difference => e
|
|
44
|
+
write_equiv_report(e.details, settings&.fetch(:format) || "json")
|
|
45
|
+
1
|
|
46
|
+
rescue Equiv::BudgetExceeded => e
|
|
47
|
+
report = { ibex_report: "equiv", schema_version: 1 }.merge(e.details)
|
|
48
|
+
write_equiv_report(report, settings&.fetch(:format) || "json")
|
|
49
|
+
2
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @rbs (Array[String] arguments) -> equiv_options
|
|
53
|
+
def equiv_options(arguments)
|
|
54
|
+
settings = default_equiv_options
|
|
55
|
+
parser = OptionParser.new do |options|
|
|
56
|
+
options.banner = "Usage: ibex equiv [options] LEFT RIGHT"
|
|
57
|
+
add_equiv_search_options(options, settings)
|
|
58
|
+
options.on("--algorithm=NAME", %w[slr lalr ielr lr1], "algorithm for grammar inputs") do |value|
|
|
59
|
+
set_local_configuration_option(settings, :algorithm, value.to_sym)
|
|
60
|
+
end
|
|
61
|
+
options.on("--mode=MODE", %w[default extended], "grammar mode") do |value|
|
|
62
|
+
set_local_configuration_option(settings, :mode, value.to_sym)
|
|
63
|
+
set_configuration_option(:mode, value.to_sym)
|
|
64
|
+
end
|
|
65
|
+
options.on("--map=OLD=NEW", "declare a nonterminal correspondence; repeatable") do |value|
|
|
66
|
+
old_name, new_name = value.split("=", 2)
|
|
67
|
+
if old_name.nil? || old_name.empty? || new_name.nil? || new_name.empty?
|
|
68
|
+
raise OptionParser::InvalidArgument, "--map must be OLD=NEW"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
settings.fetch(:rule_map)[old_name] = new_name
|
|
72
|
+
end
|
|
73
|
+
options.on("--format=FORMAT", %w[json text], "json or text") { |value| settings[:format] = value }
|
|
74
|
+
options.on("--help", "show help") { settings[:help] = options.to_s }
|
|
75
|
+
end
|
|
76
|
+
settings[:paths] = parser.parse(arguments)
|
|
77
|
+
settings[:algorithm] = local_configuration_value(settings, "parser.algorithm")
|
|
78
|
+
settings
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# @rbs () -> equiv_options
|
|
82
|
+
def default_equiv_options
|
|
83
|
+
{
|
|
84
|
+
paths: [], sample_count: 100, seed: 0, max_tokens: 8, max_configurations: 50_000,
|
|
85
|
+
max_actions: Equiv::DEFAULT_MAX_ACTIONS, max_stack: Equiv::DEFAULT_MAX_STACK,
|
|
86
|
+
algorithm: Configuration::Registry.fetch("parser.algorithm").default,
|
|
87
|
+
mode: Configuration::Registry.fetch("grammar.mode").default, format: "json", rule_map: {},
|
|
88
|
+
configuration_explicit: []
|
|
89
|
+
}
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @rbs (OptionParser options, equiv_options settings) -> void
|
|
93
|
+
def add_equiv_search_options(options, settings)
|
|
94
|
+
options.on("--samples=N", Integer, "samples generated in each direction") do |value|
|
|
95
|
+
settings[:sample_count] = positive_equiv_option(value, "samples")
|
|
96
|
+
end
|
|
97
|
+
options.on("--seed=N", Integer, "deterministic sampling seed") { |value| settings[:seed] = value }
|
|
98
|
+
options.on("--max-tokens=N", Integer, "maximum counterexample length") do |value|
|
|
99
|
+
settings[:max_tokens] = positive_equiv_option(value, "max-tokens")
|
|
100
|
+
end
|
|
101
|
+
options.on("--max-configurations=N", Integer, "product-state exploration budget") do |value|
|
|
102
|
+
settings[:max_configurations] = positive_equiv_option(value, "max-configurations")
|
|
103
|
+
end
|
|
104
|
+
options.on("--max-actions=N", Integer, "actions per simulated token sequence") do |value|
|
|
105
|
+
settings[:max_actions] = positive_equiv_option(value, "max-actions")
|
|
106
|
+
end
|
|
107
|
+
options.on("--max-stack=N", Integer, "simulated parser stack depth") do |value|
|
|
108
|
+
settings[:max_stack] = positive_equiv_option(value, "max-stack")
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# @rbs (String path, Symbol algorithm, explicit: bool) -> IR::Automaton
|
|
113
|
+
def load_equiv_automaton(path, algorithm, explicit:)
|
|
114
|
+
source = File.binread(path)
|
|
115
|
+
if source.lstrip.start_with?("{")
|
|
116
|
+
value = IR::Validator.validate(source)
|
|
117
|
+
if value.is_a?(IR::Automaton)
|
|
118
|
+
raise Ibex::Error, "(cli):1:1: --algorithm cannot be combined with Automaton IR analysis input" if explicit
|
|
119
|
+
|
|
120
|
+
return value
|
|
121
|
+
end
|
|
122
|
+
return build_equiv_automaton(value, algorithm, explicit) if value.is_a?(IR::Grammar)
|
|
123
|
+
|
|
124
|
+
raise Ibex::Error, "#{path}:1:1: equiv does not accept Lexer IR"
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
build_equiv_automaton(normalize_grammar_path(path), algorithm, explicit)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# @rbs (IR::Grammar grammar, Symbol algorithm, bool algorithm_explicit) -> IR::Automaton
|
|
131
|
+
def build_equiv_automaton(grammar, algorithm, algorithm_explicit)
|
|
132
|
+
explicit_keys = algorithm_explicit ? [:algorithm] : [] #: Array[Symbol]
|
|
133
|
+
active = activate_analysis_grammar(
|
|
134
|
+
grammar, options: { algorithm: algorithm }, explicit_keys: explicit_keys
|
|
135
|
+
)
|
|
136
|
+
LALR::Builder.new(
|
|
137
|
+
active, algorithm: configuration_value("parser.algorithm"),
|
|
138
|
+
entry_isolation: configuration_value("parser.entries") == :isolated
|
|
139
|
+
).build
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# @rbs (Hash[Symbol, Object?] report, String format) -> void
|
|
143
|
+
def write_equiv_report(report, format)
|
|
144
|
+
if format == "json"
|
|
145
|
+
@stdout.puts(JSON.pretty_generate(report))
|
|
146
|
+
else
|
|
147
|
+
@stdout.puts("result=#{report.fetch(:result)}")
|
|
148
|
+
@stdout.puts("witness=#{report[:witness].inspect}") if report[:witness]
|
|
149
|
+
@stdout.puts(report.fetch(:statement))
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# @rbs (equiv_options settings) -> bool
|
|
154
|
+
def algorithm_explicit_equiv?(settings)
|
|
155
|
+
settings.fetch(:configuration_explicit).include?(:algorithm)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# @rbs!
|
|
159
|
+
# private def activate_analysis_grammar: (IR::Grammar, ?options: Hash[Symbol, Object?],
|
|
160
|
+
# ?explicit_keys: Array[Symbol]) -> IR::Grammar
|
|
161
|
+
|
|
162
|
+
# @rbs (Integer value, String name) -> Integer
|
|
163
|
+
def positive_equiv_option(value, name)
|
|
164
|
+
return value if value.positive?
|
|
165
|
+
|
|
166
|
+
raise OptionParser::InvalidArgument, "--#{name} must be positive"
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|