ibex 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +89 -123
- data/docs/architecture.md +477 -31
- 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 +106 -0
- data/docs/cst.md +237 -0
- data/docs/decisions/0000-template.md +24 -0
- data/docs/decisions/0001-separate-ir-pipeline.md +34 -0
- data/docs/decisions/0002-opaque-user-code-boundary.md +32 -0
- data/docs/decisions/0003-self-hosted-grammar-frontend.md +32 -0
- data/docs/decisions/0004-shared-semantic-and-lossless-source-model.md +33 -0
- data/docs/decisions/0005-contained-grammar-composition.md +34 -0
- data/docs/decisions/0006-bounded-structural-grammar-lowering.md +32 -0
- data/docs/decisions/0007-shared-parser-construction-pipeline.md +33 -0
- data/docs/decisions/0008-versioned-runtime-package-boundary.md +36 -0
- data/docs/decisions/0009-isolated-parser-sessions.md +34 -0
- data/docs/decisions/0010-committed-runtime-observation.md +34 -0
- data/docs/decisions/0011-versioned-semantic-action-boundary.md +37 -0
- data/docs/decisions/0012-bounded-nonexecuting-analysis.md +37 -0
- data/docs/decisions/0013-transactional-generation-publication.md +37 -0
- data/docs/decisions/0014-versioned-generated-lexer.md +35 -0
- data/docs/decisions/0015-worker-isolated-browser-analysis.md +32 -0
- data/docs/decisions/0016-red-green-concrete-syntax.md +34 -0
- data/docs/decisions/0017-persistent-syntax-artifacts.md +35 -0
- data/docs/decisions/0018-conservative-incremental-syntax-reuse.md +38 -0
- data/docs/decisions/0019-runtime-syntax-session-boundary.md +51 -0
- data/docs/decisions/0020-grammar-ir-parser-contract.md +65 -0
- data/docs/decisions/0021-data-only-parser-table-sidecar.md +50 -0
- data/docs/decisions/0022-manifest-bound-verification-report.md +77 -0
- data/docs/decisions/0023-syntax-only-repair-results.md +48 -0
- data/docs/decisions/0024-direct-ielr-construction.md +42 -0
- data/docs/decisions/README.md +74 -0
- data/docs/declarative-configuration.md +262 -0
- data/docs/development.md +306 -0
- data/docs/direct-ielr-decision.md +120 -0
- data/docs/direct-multi-entry-decision.md +82 -0
- data/docs/editor-setup.md +26 -0
- data/docs/error-ux-review-rubric-v1.md +117 -0
- data/docs/error-ux-reviews/v1/records/README.md +22 -0
- data/docs/error-ux-round2-review-status-v1.json +27 -0
- data/docs/error-ux-round2-reviews/v1/records/README.md +30 -0
- data/docs/error-ux-round2-v1.json +1581 -0
- data/docs/error-ux-round2.md +111 -0
- data/docs/error-ux.md +114 -0
- data/docs/getting-started.md +80 -0
- data/docs/grammar-reference.md +629 -18
- data/docs/ielr-design.md +43 -0
- data/docs/ielr.md +92 -0
- data/docs/ja/bison-import.md +51 -0
- data/docs/ja/stable-api.md +53 -0
- data/docs/lexer-construction-profile.md +109 -0
- data/docs/lexer-migration.md +56 -0
- data/docs/maturity.md +128 -0
- data/docs/project-site-strategy.md +54 -0
- data/docs/racc-migration-evidence.md +45 -0
- data/docs/racc-migration.md +45 -6
- data/docs/release-readiness.md +221 -0
- data/docs/repair-semantics.md +123 -0
- data/docs/runtime-abi-evolution.md +307 -0
- data/docs/stability.md +234 -0
- 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/examples/README.md +60 -0
- data/examples/calculator.y +44 -0
- data/examples/csv.y +32 -0
- data/examples/ini.y +70 -0
- data/examples/json.y +48 -0
- data/examples/tiny_language.y +75 -0
- data/lib/ibex/analysis/digraph.rb +128 -0
- data/lib/ibex/analysis/sets.rb +5 -4
- data/lib/ibex/analysis.rb +1 -0
- data/lib/ibex/artifact_set.rb +63 -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 +75 -0
- 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/counterexample_options.rb +6 -2
- data/lib/ibex/cli/coverage.rb +173 -0
- data/lib/ibex/cli/debug.rb +106 -0
- data/lib/ibex/cli/diagnostics.rb +136 -0
- data/lib/ibex/cli/documentation.rb +70 -0
- data/lib/ibex/cli/equiv.rb +169 -0
- data/lib/ibex/cli/error_messages.rb +184 -0
- data/lib/ibex/cli/explain.rb +85 -0
- data/lib/ibex/cli/fix.rb +203 -0
- data/lib/ibex/cli/formatting.rb +387 -0
- data/lib/ibex/cli/fuzz.rb +200 -0
- data/lib/ibex/cli/fuzz_regressions.rb +145 -0
- data/lib/ibex/cli/generation_artifacts.rb +189 -0
- data/lib/ibex/cli/generation_error_messages.rb +39 -0
- data/lib/ibex/cli/grammar_tests.rb +140 -0
- data/lib/ibex/cli/ir_tools.rb +128 -0
- data/lib/ibex/cli/lsp.rb +33 -0
- data/lib/ibex/cli/outputs.rb +133 -23
- data/lib/ibex/cli/racc_migration.rb +87 -0
- data/lib/ibex/cli/reduce.rb +202 -0
- data/lib/ibex/cli/reduce_reporting.rb +71 -0
- data/lib/ibex/cli/samples.rb +118 -0
- data/lib/ibex/cli/verify.rb +116 -0
- data/lib/ibex/cli/watch.rb +104 -0
- data/lib/ibex/cli.rb +825 -55
- data/lib/ibex/codegen/action_locations.rb +103 -0
- data/lib/ibex/codegen/action_method_source.rb +209 -0
- data/lib/ibex/codegen/action_source.rb +119 -0
- data/lib/ibex/codegen/ambiguity.rb +174 -0
- data/lib/ibex/codegen/cst_metadata.rb +171 -0
- data/lib/ibex/codegen/documentation.rb +170 -0
- data/lib/ibex/codegen/explain.rb +380 -0
- data/lib/ibex/codegen/generated_action_abi.rb +293 -0
- data/lib/ibex/codegen/html.rb +94 -10
- data/lib/ibex/codegen/mermaid.rb +43 -0
- data/lib/ibex/codegen/railroad.rb +197 -0
- data/lib/ibex/codegen/railroad_documentation.rb +59 -0
- data/lib/ibex/codegen/rbs.rb +331 -2
- data/lib/ibex/codegen/report.rb +67 -15
- data/lib/ibex/codegen/ruby.rb +305 -66
- data/lib/ibex/codegen/ruby_actions.rb +146 -0
- data/lib/ibex/codegen/ruby_ast.rb +121 -0
- data/lib/ibex/codegen/ruby_error_messages.rb +28 -0
- data/lib/ibex/codegen/ruby_lexer.rb +83 -0
- data/lib/ibex/codegen/ruby_syntax.rb +96 -0
- data/lib/ibex/codegen/ruby_table_metadata.rb +57 -0
- data/lib/ibex/codegen/ruby_value_printers.rb +56 -0
- data/lib/ibex/codegen/symbol_labels.rb +1 -1
- 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 +198 -0
- data/lib/ibex/coverage/event_stream.rb +103 -0
- data/lib/ibex/coverage/report.rb +267 -0
- data/lib/ibex/coverage/runtime_event_validator.rb +169 -0
- data/lib/ibex/coverage.rb +13 -0
- data/lib/ibex/delta_reducer.rb +99 -0
- data/lib/ibex/diff.rb +140 -0
- data/lib/ibex/equiv/machine.rb +135 -0
- data/lib/ibex/equiv.rb +373 -0
- data/lib/ibex/error_messages/parser.rb +159 -0
- data/lib/ibex/error_messages/parser_v2.rb +198 -0
- data/lib/ibex/error_messages/renderer.rb +65 -0
- data/lib/ibex/error_messages/sentence_search.rb +196 -0
- data/lib/ibex/error_messages/update.rb +169 -0
- data/lib/ibex/error_messages.rb +165 -0
- data/lib/ibex/fix.rb +557 -0
- data/lib/ibex/frontend/ast.rb +166 -7
- data/lib/ibex/frontend/bootstrap_parser.rb +40 -4
- data/lib/ibex/frontend/diagnostic.rb +81 -0
- data/lib/ibex/frontend/diagnostic_recovery.rb +268 -0
- data/lib/ibex/frontend/dsl.rb +66 -7
- data/lib/ibex/frontend/formatter.rb +453 -0
- data/lib/ibex/frontend/generated_parser.rb +644 -190
- data/lib/ibex/frontend/generated_parser_base.rb +170 -32
- data/lib/ibex/frontend/generated_parser_includes.rb +51 -0
- data/lib/ibex/frontend/generated_parser_metadata.rb +61 -0
- data/lib/ibex/frontend/generated_parser_parameters.rb +60 -0
- data/lib/ibex/frontend/generation.rb +33 -0
- data/lib/ibex/frontend/lexer.rb +162 -10
- data/lib/ibex/frontend/lexer_recovery.rb +84 -0
- data/lib/ibex/frontend/parser/declarations.rb +262 -11
- data/lib/ibex/frontend/parser/parameters.rb +82 -0
- data/lib/ibex/frontend/parser/rules.rb +43 -6
- data/lib/ibex/frontend/parser.rb +182 -4
- data/lib/ibex/frontend/parser_configuration_support.rb +56 -0
- data/lib/ibex/frontend/regenerator.rb +27 -1
- data/lib/ibex/frontend/resolution.rb +70 -0
- data/lib/ibex/frontend/resolver.rb +217 -0
- data/lib/ibex/frontend/rule_documentation.rb +104 -0
- data/lib/ibex/frontend/source_cursor.rb +133 -9
- data/lib/ibex/frontend/source_document.rb +229 -0
- data/lib/ibex/frontend/source_loader.rb +150 -0
- data/lib/ibex/frontend/source_span.rb +89 -0
- data/lib/ibex/frontend/token_adapter/declaration_document_state.rb +47 -0
- data/lib/ibex/frontend/token_adapter/declaration_lexer_state.rb +83 -0
- data/lib/ibex/frontend/token_adapter/declaration_state.rb +244 -22
- data/lib/ibex/frontend/token_adapter/delimiter_tracker.rb +8 -2
- data/lib/ibex/frontend/token_adapter/rule_state.rb +60 -2
- data/lib/ibex/frontend/token_adapter.rb +18 -3
- data/lib/ibex/frontend.rb +14 -2
- data/lib/ibex/fuzz.rb +219 -0
- data/lib/ibex/generation_input.rb +57 -0
- data/lib/ibex/generation_manifest.rb +211 -0
- data/lib/ibex/generation_transaction.rb +261 -0
- data/lib/ibex/generation_transaction_recovery.rb +109 -0
- data/lib/ibex/generation_transaction_validation.rb +196 -0
- data/lib/ibex/grammar_tests.rb +206 -0
- data/lib/ibex/ir/automaton_ir.rb +86 -11
- data/lib/ibex/ir/grammar_ir.rb +170 -26
- data/lib/ibex/ir/lexer_ir.rb +76 -0
- data/lib/ibex/ir/parser_contract.rb +135 -0
- data/lib/ibex/ir/serialize.rb +268 -50
- data/lib/ibex/ir/validator/automaton.rb +375 -0
- data/lib/ibex/ir/validator/base.rb +147 -0
- data/lib/ibex/ir/validator/grammar.rb +634 -0
- data/lib/ibex/ir/validator/lexer.rb +113 -0
- data/lib/ibex/ir/validator.rb +63 -0
- data/lib/ibex/ir.rb +71 -5
- data/lib/ibex/lalr/build_metrics.rb +71 -0
- data/lib/ibex/lalr/builder.rb +514 -52
- data/lib/ibex/lalr/conflict.rb +1 -0
- data/lib/ibex/lalr/conflict_search.rb +26 -9
- data/lib/ibex/lalr/counterexample.rb +38 -18
- data/lib/ibex/lalr/direct_lookaheads.rb +289 -0
- 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 +166 -0
- 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/on_error_reductions.rb +74 -0
- data/lib/ibex/lalr/unreachable_states.rb +80 -0
- data/lib/ibex/lalr.rb +59 -1
- data/lib/ibex/location.rb +129 -0
- data/lib/ibex/lsp/document_handlers.rb +68 -0
- data/lib/ibex/lsp/document_store.rb +264 -0
- data/lib/ibex/lsp/document_store_diagnostics.rb +44 -0
- data/lib/ibex/lsp/document_store_validation.rb +61 -0
- data/lib/ibex/lsp/initialization_handlers.rb +80 -0
- data/lib/ibex/lsp/navigation_handlers.rb +70 -0
- data/lib/ibex/lsp/parser_configuration_assistance.rb +149 -0
- data/lib/ibex/lsp/position_codec.rb +113 -0
- data/lib/ibex/lsp/protocol_error.rb +33 -0
- data/lib/ibex/lsp/request_handlers.rb +46 -0
- data/lib/ibex/lsp/request_support.rb +94 -0
- data/lib/ibex/lsp/server.rb +148 -0
- data/lib/ibex/lsp/symbol_index.rb +241 -0
- data/lib/ibex/lsp/symbol_index_builder.rb +277 -0
- data/lib/ibex/lsp/symbol_index_precedence_references.rb +44 -0
- data/lib/ibex/lsp/symbol_index_source_queries.rb +61 -0
- data/lib/ibex/lsp/symbol_occurrence.rb +23 -0
- data/lib/ibex/lsp/transport.rb +128 -0
- data/lib/ibex/lsp/workspace.rb +128 -0
- data/lib/ibex/lsp/workspace_analyzer.rb +199 -0
- data/lib/ibex/lsp.rb +33 -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 +142 -7
- data/lib/ibex/normalize/diagnostics.rb +94 -24
- data/lib/ibex/normalize/expander.rb +64 -59
- data/lib/ibex/normalize/expression.rb +63 -40
- data/lib/ibex/normalize/grammar_builder.rb +26 -0
- data/lib/ibex/normalize/inline_expansion.rb +465 -0
- data/lib/ibex/normalize/inline_validation.rb +174 -0
- data/lib/ibex/normalize/lexer.rb +131 -0
- data/lib/ibex/normalize/named_references.rb +60 -0
- data/lib/ibex/normalize/nodes.rb +46 -0
- data/lib/ibex/normalize/parameter_ebnf_lowering.rb +70 -0
- data/lib/ibex/normalize/parameter_lowering.rb +143 -0
- data/lib/ibex/normalize/parameter_substitution.rb +125 -0
- data/lib/ibex/normalize/parameter_validation.rb +140 -0
- data/lib/ibex/normalize/parameters.rb +226 -0
- data/lib/ibex/normalize/parser_configuration.rb +70 -0
- data/lib/ibex/normalize/recovery_declarations.rb +84 -0
- data/lib/ibex/normalize.rb +172 -17
- data/lib/ibex/racc_migration/checker.rb +122 -0
- data/lib/ibex/racc_migration/harness.rb +177 -0
- data/lib/ibex/racc_migration/report.rb +97 -0
- data/lib/ibex/racc_migration.rb +12 -0
- data/lib/ibex/rake_task.rb +116 -0
- data/lib/ibex/samples.rb +216 -0
- 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 +55 -0
- data/lib/ibex/table_simulation/simulator.rb +253 -0
- data/lib/ibex/table_simulation/step.rb +62 -0
- data/lib/ibex/table_simulation/text.rb +31 -0
- data/lib/ibex/table_simulation.rb +13 -0
- data/lib/ibex/tables.rb +22 -69
- 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 +181 -0
- data/lib/ibex/watch/source_snapshot.rb +98 -0
- data/lib/ibex/watch.rb +11 -0
- data/lib/ibex.rb +35 -1
- data/schema/automaton-ir-definitions.schema.json +401 -0
- data/schema/automaton-ir.schema.json +65 -0
- data/schema/benchmark-v1.schema.json +212 -0
- data/schema/benchmark-v2.schema.json +61 -0
- 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/cst-v1.json +170 -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/error-ux-v1.schema.json +258 -0
- data/schema/explain-v1.schema.json +495 -0
- 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/frontend-diagnostics-v1.schema.json +154 -0
- data/schema/fuzz-regression-v1.schema.json +79 -0
- data/schema/fuzz-v1.schema.json +114 -0
- data/schema/generation-manifest-v1.schema.json +115 -0
- data/schema/grammar-ir-extensions.schema.json +734 -0
- data/schema/grammar-ir-foundation.schema.json +426 -0
- data/schema/grammar-ir.schema.json +271 -0
- data/schema/ielr-benchmark-v1.schema.json +85 -0
- data/schema/lexer-ir-v1.schema.json +215 -0
- data/schema/lexer-profile-v1.schema.json +491 -0
- data/schema/metrics-v1.schema.json +60 -0
- data/schema/migration-check-v1.schema.json +60 -0
- data/schema/performance-comparison-v1.schema.json +395 -0
- data/schema/public-performance-comparison-v1.schema.json +506 -0
- data/schema/public-performance-profile-v1.schema.json +360 -0
- data/schema/reduce-v1.schema.json +22 -0
- data/schema/reduce-v2.schema.json +63 -0
- data/schema/runtime-coverage-v1.schema.json +86 -0
- data/schema/runtime-event-v1.schema.json +308 -0
- data/schema/table-artifact-v1.schema.json +377 -0
- data/schema/table-simulation-v1.schema.json +70 -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/artifact_set.rbs +37 -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 +28 -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/counterexample_options.rbs +2 -0
- data/sig/ibex/cli/coverage.rbs +53 -0
- data/sig/ibex/cli/debug.rbs +28 -0
- data/sig/ibex/cli/diagnostics.rbs +51 -0
- data/sig/ibex/cli/documentation.rbs +29 -0
- data/sig/ibex/cli/equiv.rbs +49 -0
- data/sig/ibex/cli/error_messages.rbs +63 -0
- data/sig/ibex/cli/explain.rbs +31 -0
- data/sig/ibex/cli/fix.rbs +53 -0
- data/sig/ibex/cli/formatting.rbs +107 -0
- data/sig/ibex/cli/fuzz.rbs +47 -0
- data/sig/ibex/cli/fuzz_regressions.rbs +40 -0
- data/sig/ibex/cli/generation_artifacts.rbs +69 -0
- data/sig/ibex/cli/generation_error_messages.rbs +19 -0
- data/sig/ibex/cli/grammar_tests.rbs +48 -0
- data/sig/ibex/cli/ir_tools.rbs +39 -0
- data/sig/ibex/cli/lsp.rbs +14 -0
- data/sig/ibex/cli/outputs.rbs +26 -3
- data/sig/ibex/cli/racc_migration.rbs +30 -0
- data/sig/ibex/cli/reduce.rbs +60 -0
- data/sig/ibex/cli/reduce_reporting.rbs +27 -0
- data/sig/ibex/cli/samples.rbs +38 -0
- data/sig/ibex/cli/verify.rbs +28 -0
- data/sig/ibex/cli/watch.rbs +43 -0
- data/sig/ibex/cli.rbs +182 -9
- data/sig/ibex/codegen/action_locations.rbs +45 -0
- data/sig/ibex/codegen/action_method_source.rbs +65 -0
- data/sig/ibex/codegen/action_source.rbs +50 -0
- data/sig/ibex/codegen/ambiguity.rbs +60 -0
- data/sig/ibex/codegen/cst_metadata.rbs +59 -0
- data/sig/ibex/codegen/documentation.rbs +50 -0
- data/sig/ibex/codegen/explain.rbs +105 -0
- data/sig/ibex/codegen/generated_action_abi.rbs +105 -0
- data/sig/ibex/codegen/html.rbs +18 -2
- data/sig/ibex/codegen/mermaid.rbs +16 -0
- data/sig/ibex/codegen/railroad.rbs +82 -0
- data/sig/ibex/codegen/railroad_documentation.rbs +31 -0
- data/sig/ibex/codegen/rbs.rbs +86 -4
- data/sig/ibex/codegen/report.rbs +16 -8
- data/sig/ibex/codegen/ruby.rbs +105 -28
- data/sig/ibex/codegen/ruby_actions.rbs +54 -0
- data/sig/ibex/codegen/ruby_ast.rbs +34 -0
- data/sig/ibex/codegen/ruby_error_messages.rbs +16 -0
- data/sig/ibex/codegen/ruby_lexer.rbs +25 -0
- data/sig/ibex/codegen/ruby_syntax.rbs +27 -0
- data/sig/ibex/codegen/ruby_table_metadata.rbs +26 -0
- data/sig/ibex/codegen/ruby_value_printers.rbs +28 -0
- 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 +78 -0
- data/sig/ibex/coverage/event_stream.rbs +44 -0
- data/sig/ibex/coverage/report.rbs +102 -0
- data/sig/ibex/coverage/runtime_event_validator.rbs +70 -0
- data/sig/ibex/coverage.rbs +7 -0
- 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/error_messages/parser.rbs +58 -0
- data/sig/ibex/error_messages/parser_v2.rbs +67 -0
- data/sig/ibex/error_messages/renderer.rbs +23 -0
- data/sig/ibex/error_messages/sentence_search.rbs +80 -0
- data/sig/ibex/error_messages/update.rbs +43 -0
- data/sig/ibex/error_messages.rbs +85 -0
- data/sig/ibex/fix.rbs +138 -0
- data/sig/ibex/frontend/ast.rbs +237 -22
- data/sig/ibex/frontend/bootstrap_parser.rbs +13 -0
- data/sig/ibex/frontend/diagnostic.rbs +53 -0
- data/sig/ibex/frontend/diagnostic_recovery.rbs +98 -0
- data/sig/ibex/frontend/dsl.rbs +33 -4
- data/sig/ibex/frontend/formatter.rbs +143 -0
- data/sig/ibex/frontend/generated_parser.rbs +228 -68
- data/sig/ibex/frontend/generated_parser_base.rbs +65 -12
- data/sig/ibex/frontend/generated_parser_includes.rbs +23 -0
- data/sig/ibex/frontend/generated_parser_metadata.rbs +23 -0
- data/sig/ibex/frontend/generated_parser_parameters.rbs +24 -0
- data/sig/ibex/frontend/generation.rbs +6 -0
- data/sig/ibex/frontend/lexer.rbs +49 -2
- data/sig/ibex/frontend/lexer_recovery.rbs +25 -0
- data/sig/ibex/frontend/parser/declarations.rbs +57 -0
- data/sig/ibex/frontend/parser/parameters.rbs +28 -0
- data/sig/ibex/frontend/parser/rules.rbs +3 -0
- data/sig/ibex/frontend/parser.rbs +66 -0
- data/sig/ibex/frontend/parser_configuration_support.rbs +27 -0
- data/sig/ibex/frontend/regenerator.rbs +11 -0
- data/sig/ibex/frontend/resolution.rbs +34 -0
- data/sig/ibex/frontend/resolver.rbs +91 -0
- data/sig/ibex/frontend/rule_documentation.rbs +42 -0
- data/sig/ibex/frontend/source_cursor.rbs +38 -5
- data/sig/ibex/frontend/source_document.rbs +119 -0
- data/sig/ibex/frontend/source_loader.rbs +66 -0
- data/sig/ibex/frontend/source_span.rbs +56 -0
- data/sig/ibex/frontend/token_adapter/declaration_document_state.rbs +21 -0
- data/sig/ibex/frontend/token_adapter/declaration_lexer_state.rbs +27 -0
- data/sig/ibex/frontend/token_adapter/declaration_state.rbs +83 -3
- data/sig/ibex/frontend/token_adapter/rule_state.rbs +20 -0
- data/sig/ibex/frontend/token_adapter.rbs +11 -2
- data/sig/ibex/frontend.rbs +1 -1
- data/sig/ibex/fuzz.rbs +71 -0
- data/sig/ibex/generation_input.rbs +37 -0
- data/sig/ibex/generation_manifest.rbs +70 -0
- data/sig/ibex/generation_transaction.rbs +82 -0
- data/sig/ibex/generation_transaction_recovery.rbs +36 -0
- data/sig/ibex/generation_transaction_validation.rbs +65 -0
- data/sig/ibex/grammar_tests.rbs +93 -0
- data/sig/ibex/ir/automaton_ir.rbs +35 -10
- data/sig/ibex/ir/grammar_ir.rbs +96 -22
- data/sig/ibex/ir/lexer_ir.rbs +57 -0
- data/sig/ibex/ir/parser_contract.rbs +69 -0
- data/sig/ibex/ir/serialize.rbs +75 -23
- data/sig/ibex/ir/validator/automaton.rbs +112 -0
- data/sig/ibex/ir/validator/base.rbs +69 -0
- data/sig/ibex/ir/validator/grammar.rbs +195 -0
- data/sig/ibex/ir/validator/lexer.rbs +37 -0
- data/sig/ibex/ir/validator.rbs +16 -0
- data/sig/ibex/ir.rbs +45 -5
- data/sig/ibex/lalr/build_metrics.rbs +60 -0
- data/sig/ibex/lalr/builder.rbs +150 -19
- data/sig/ibex/lalr/conflict_search.rbs +12 -5
- data/sig/ibex/lalr/counterexample.rbs +20 -14
- data/sig/ibex/lalr/direct_lookaheads.rbs +93 -0
- 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 +71 -0
- 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/on_error_reductions.rbs +22 -0
- data/sig/ibex/lalr/unreachable_states.rbs +25 -0
- data/sig/ibex/lalr.rbs +17 -1
- data/sig/ibex/location.rbs +67 -0
- data/sig/ibex/lsp/document_handlers.rbs +24 -0
- data/sig/ibex/lsp/document_store.rbs +94 -0
- data/sig/ibex/lsp/document_store_diagnostics.rbs +20 -0
- data/sig/ibex/lsp/document_store_validation.rbs +26 -0
- data/sig/ibex/lsp/initialization_handlers.rbs +30 -0
- data/sig/ibex/lsp/navigation_handlers.rbs +33 -0
- data/sig/ibex/lsp/parser_configuration_assistance.rbs +49 -0
- data/sig/ibex/lsp/position_codec.rbs +44 -0
- data/sig/ibex/lsp/protocol_error.rbs +32 -0
- data/sig/ibex/lsp/request_handlers.rbs +26 -0
- data/sig/ibex/lsp/request_support.rbs +40 -0
- data/sig/ibex/lsp/server.rbs +55 -0
- data/sig/ibex/lsp/symbol_index.rbs +77 -0
- data/sig/ibex/lsp/symbol_index_builder.rbs +88 -0
- data/sig/ibex/lsp/symbol_index_precedence_references.rbs +18 -0
- data/sig/ibex/lsp/symbol_index_source_queries.rbs +26 -0
- data/sig/ibex/lsp/symbol_occurrence.rbs +31 -0
- data/sig/ibex/lsp/transport.rbs +47 -0
- data/sig/ibex/lsp/workspace.rbs +42 -0
- data/sig/ibex/lsp/workspace_analyzer.rbs +69 -0
- data/sig/ibex/lsp.rbs +7 -0
- data/sig/ibex/messages.rbs +26 -0
- data/sig/ibex/metrics.rbs +50 -0
- data/sig/ibex/normalize/declarations.rbs +31 -0
- data/sig/ibex/normalize/diagnostics.rbs +13 -4
- data/sig/ibex/normalize/expander.rbs +22 -16
- data/sig/ibex/normalize/expression.rbs +11 -9
- data/sig/ibex/normalize/grammar_builder.rbs +11 -0
- data/sig/ibex/normalize/inline_expansion.rbs +129 -0
- data/sig/ibex/normalize/inline_validation.rbs +40 -0
- data/sig/ibex/normalize/lexer.rbs +37 -0
- data/sig/ibex/normalize/named_references.rbs +20 -0
- data/sig/ibex/normalize/nodes.rbs +14 -0
- data/sig/ibex/normalize/parameter_ebnf_lowering.rbs +33 -0
- data/sig/ibex/normalize/parameter_lowering.rbs +35 -0
- data/sig/ibex/normalize/parameter_substitution.rbs +42 -0
- data/sig/ibex/normalize/parameter_validation.rbs +44 -0
- data/sig/ibex/normalize/parameters.rbs +51 -0
- data/sig/ibex/normalize/parser_configuration.rbs +23 -0
- data/sig/ibex/normalize/recovery_declarations.rbs +24 -0
- data/sig/ibex/normalize.rbs +129 -18
- data/sig/ibex/racc_migration/checker.rbs +36 -0
- data/sig/ibex/racc_migration/harness.rbs +16 -0
- data/sig/ibex/racc_migration/report.rbs +55 -0
- data/sig/ibex/racc_migration.rbs +8 -0
- data/sig/ibex/rake_task.rbs +51 -0
- data/sig/ibex/samples.rbs +60 -0
- 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 +36 -0
- data/sig/ibex/table_simulation/simulator.rbs +98 -0
- data/sig/ibex/table_simulation/step.rbs +42 -0
- data/sig/ibex/table_simulation/text.rbs +14 -0
- data/sig/ibex/table_simulation.rbs +7 -0
- data/sig/ibex/tables.rbs +10 -35
- 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 +58 -0
- data/sig/ibex/watch/source_snapshot.rbs +46 -0
- data/sig/ibex/watch.rbs +7 -0
- data/sig/ibex.rbs +2 -0
- metadata +524 -19
- data/.rubocop.yml +0 -43
- data/CHANGELOG.md +0 -30
- data/Rakefile +0 -25
- data/Steepfile +0 -10
- data/docs/compat-notes.md +0 -37
- data/docs/lexer-coverage.md +0 -14
- data/docs/phase10-extensions.md +0 -27
- data/gemfiles/Gemfile +0 -7
- data/gemfiles/Gemfile.lock +0 -98
- data/lib/ibex/frontend/grammar.y +0 -156
- data/lib/ibex/runtime/parser.rb +0 -360
- data/lib/ibex/runtime.rb +0 -8
- data/sig/ibex/runtime/parser.rbs +0 -167
- data/sig/ibex/runtime.rbs +0 -6
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "optparse"
|
|
5
|
+
require_relative "../frontend"
|
|
6
|
+
|
|
7
|
+
module Ibex
|
|
8
|
+
# Batch frontend diagnostics subcommand.
|
|
9
|
+
module CLIDiagnostics
|
|
10
|
+
DIAGNOSTICS_SCHEMA_VERSION = 1 #: Integer
|
|
11
|
+
DEFAULT_MAX_DIAGNOSTICS = 20 #: Integer
|
|
12
|
+
|
|
13
|
+
# @rbs!
|
|
14
|
+
# type diagnostic_settings = Hash[Symbol, untyped]
|
|
15
|
+
#
|
|
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
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
# @rbs (Array[String] arguments) -> Integer
|
|
23
|
+
def run_diagnose_command(arguments)
|
|
24
|
+
settings = {
|
|
25
|
+
format: "text", max_diagnostics: DEFAULT_MAX_DIAGNOSTICS,
|
|
26
|
+
mode: Configuration::Registry.fetch("grammar.mode").default, configuration_explicit: []
|
|
27
|
+
} #: diagnostic_settings
|
|
28
|
+
parser = diagnostics_option_parser(settings)
|
|
29
|
+
remaining = parser.parse(arguments)
|
|
30
|
+
settings[:mode] = local_configuration_value(settings, "grammar.mode")
|
|
31
|
+
if settings[:help]
|
|
32
|
+
@stdout.puts(parser)
|
|
33
|
+
return 0
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
path = input_path(remaining)
|
|
37
|
+
result = Frontend::Parser.new(File.binread(path), file: path, mode: settings.fetch(:mode))
|
|
38
|
+
.parse_with_diagnostics(max_diagnostics: settings.fetch(:max_diagnostics))
|
|
39
|
+
result = resolve_diagnostic_result(result, path, settings.fetch(:mode)) if result.success?
|
|
40
|
+
write_diagnostics(result, format: settings.fetch(:format))
|
|
41
|
+
result.success? ? 0 : 1
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Cross-file recovery is deliberately bounded to the first resolver error.
|
|
45
|
+
# @rbs (Frontend::ParseResult result, String path, Symbol mode) -> Frontend::ParseResult
|
|
46
|
+
def resolve_diagnostic_result(result, path, mode)
|
|
47
|
+
Frontend::Resolver.new(path, mode: mode).resolve
|
|
48
|
+
result
|
|
49
|
+
rescue Frontend::ResolutionIOError
|
|
50
|
+
raise
|
|
51
|
+
rescue Ibex::Error => e
|
|
52
|
+
Frontend::ParseResult.new(diagnostics: [resolution_diagnostic(e, path)], ast: nil, document: nil)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @rbs (Ibex::Error error, String fallback_file) -> Frontend::Diagnostic
|
|
56
|
+
def resolution_diagnostic(error, fallback_file)
|
|
57
|
+
match = error.message.match(/\A(.+):(\d+):(\d+): (.*)\z/m)
|
|
58
|
+
location = if match
|
|
59
|
+
Frontend::Location.new(
|
|
60
|
+
file: match[1].to_s, line: Integer(match[2].to_s), column: Integer(match[3].to_s)
|
|
61
|
+
)
|
|
62
|
+
else
|
|
63
|
+
Frontend::Location.new(file: fallback_file, line: 1, column: 1)
|
|
64
|
+
end
|
|
65
|
+
message = match ? match[4].to_s : error.message
|
|
66
|
+
Frontend::Diagnostic.new(
|
|
67
|
+
code: "frontend.resolution_error", phase: :syntax, message: message,
|
|
68
|
+
location: location, rendered: error.message
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @rbs (diagnostic_settings settings) -> OptionParser
|
|
73
|
+
def diagnostics_option_parser(settings)
|
|
74
|
+
OptionParser.new do |options|
|
|
75
|
+
options.banner = "Usage: ibex diagnose [options] grammarfile"
|
|
76
|
+
options.on("--format=FORMAT", %w[text json], "text or json") { |value| settings[:format] = value }
|
|
77
|
+
options.on("--max-diagnostics=N", "positive diagnostic limit") do |value|
|
|
78
|
+
settings[:max_diagnostics] = positive_diagnostic_limit(value)
|
|
79
|
+
end
|
|
80
|
+
options.on("--mode=MODE", %w[default extended], "grammar mode") do |value|
|
|
81
|
+
set_local_configuration_option(settings, :mode, value.to_sym)
|
|
82
|
+
end
|
|
83
|
+
options.on("--help", "show help") { settings[:help] = true }
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# @rbs (String value) -> Integer
|
|
88
|
+
def positive_diagnostic_limit(value)
|
|
89
|
+
limit = Integer(value, 10)
|
|
90
|
+
return limit if limit.positive?
|
|
91
|
+
|
|
92
|
+
raise OptionParser::InvalidArgument, "max diagnostics must be positive"
|
|
93
|
+
rescue ArgumentError
|
|
94
|
+
raise OptionParser::InvalidArgument, "max diagnostics must be a positive integer"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# @rbs (Frontend::ParseResult result, format: String) -> void
|
|
98
|
+
def write_diagnostics(result, format:)
|
|
99
|
+
if format == "json"
|
|
100
|
+
@stdout.puts(JSON.pretty_generate(diagnostics_document(result)))
|
|
101
|
+
else
|
|
102
|
+
result.diagnostics.each { |diagnostic| @stdout.puts(localized_diagnostic_text(diagnostic)) }
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# @rbs (Frontend::ParseResult result) -> Hash[String, Object?]
|
|
107
|
+
def diagnostics_document(result)
|
|
108
|
+
{
|
|
109
|
+
"ibex_diagnostics" => "frontend",
|
|
110
|
+
"schema_version" => DIAGNOSTICS_SCHEMA_VERSION,
|
|
111
|
+
"success" => result.success?,
|
|
112
|
+
"ast_available" => !result.ast.nil?,
|
|
113
|
+
"diagnostics" => result.diagnostics.map { |diagnostic| localized_diagnostic_hash(diagnostic) }
|
|
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
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "optparse"
|
|
4
|
+
require_relative "../frontend"
|
|
5
|
+
require_relative "../normalize"
|
|
6
|
+
require_relative "../codegen/documentation"
|
|
7
|
+
|
|
8
|
+
module Ibex
|
|
9
|
+
# Generates standalone grammar documentation from the canonical include closure.
|
|
10
|
+
module CLIDocumentation
|
|
11
|
+
# @rbs!
|
|
12
|
+
# type documentation_settings = Hash[Symbol, untyped]
|
|
13
|
+
#
|
|
14
|
+
# private def input_path: (Array[String]) -> String
|
|
15
|
+
# private def same_file_target?: (String left, String right) -> bool
|
|
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
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
# @rbs (Array[String] arguments) -> Integer
|
|
23
|
+
def run_documentation_command(arguments)
|
|
24
|
+
settings = {
|
|
25
|
+
format: "markdown", mode: Configuration::Registry.fetch("grammar.mode").default,
|
|
26
|
+
configuration_explicit: []
|
|
27
|
+
} #: documentation_settings
|
|
28
|
+
parser = documentation_option_parser(settings)
|
|
29
|
+
remaining = parser.parse(arguments)
|
|
30
|
+
settings[:mode] = local_configuration_value(settings, "grammar.mode")
|
|
31
|
+
if settings[:help]
|
|
32
|
+
@stdout.puts(parser)
|
|
33
|
+
return 0
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
path = input_path(remaining)
|
|
37
|
+
output = settings[:output]
|
|
38
|
+
resolution = Frontend::Resolver.new(path, mode: settings.fetch(:mode)).resolve
|
|
39
|
+
reject_documentation_output_collision(output, resolution.files) if output
|
|
40
|
+
grammar = Normalizer.new(resolution, mode: settings.fetch(:mode)).normalize
|
|
41
|
+
rendered = Codegen::Documentation.render(grammar, format: settings.fetch(:format))
|
|
42
|
+
output ? atomic_write_ir(output, rendered) : @stdout.write(rendered)
|
|
43
|
+
0
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @rbs (String output, Array[String] grammar_files) -> void
|
|
47
|
+
def reject_documentation_output_collision(output, grammar_files)
|
|
48
|
+
collision = grammar_files.find { |grammar_file| same_file_target?(grammar_file, output) }
|
|
49
|
+
return unless collision
|
|
50
|
+
|
|
51
|
+
raise Ibex::Error,
|
|
52
|
+
"(cli):1:1: doc input and output paths must be distinct; output aliases grammar source #{collision}"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @rbs (documentation_settings settings) -> OptionParser
|
|
56
|
+
def documentation_option_parser(settings)
|
|
57
|
+
OptionParser.new do |options|
|
|
58
|
+
options.banner = "Usage: ibex doc [options] grammarfile"
|
|
59
|
+
options.on("--format=FORMAT", Codegen::Documentation::FORMATS, "markdown, html, or railroad") do |value|
|
|
60
|
+
settings[:format] = value
|
|
61
|
+
end
|
|
62
|
+
options.on("-o FILE", "--output=FILE", "write atomically to FILE") { |value| settings[:output] = value }
|
|
63
|
+
options.on("--mode=MODE", %w[default extended], "grammar mode") do |value|
|
|
64
|
+
set_local_configuration_option(settings, :mode, value.to_sym)
|
|
65
|
+
end
|
|
66
|
+
options.on("--help", "show help") { settings[:help] = true }
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
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
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "tempfile"
|
|
4
|
+
require_relative "../error_messages"
|
|
5
|
+
require_relative "../ir"
|
|
6
|
+
|
|
7
|
+
module Ibex
|
|
8
|
+
# CLI subcommand and generation-file handling for example-keyed errors.
|
|
9
|
+
module CLIErrorMessages
|
|
10
|
+
# @rbs!
|
|
11
|
+
# private def print_help: (OptionParser) -> Integer
|
|
12
|
+
# private def input_path: (Array[String]) -> String
|
|
13
|
+
# private def warning_categories: (String) -> Array[Symbol]
|
|
14
|
+
# private def report_status: (String) -> void
|
|
15
|
+
# private def handle_grammar_warnings: (IR::Grammar, String) -> void
|
|
16
|
+
# private def build_automaton: (IR::Grammar, String) -> IR::Automaton
|
|
17
|
+
# private def prepare_loaded_automaton: (IR::Automaton, String) -> void
|
|
18
|
+
# private def default_output_path: (String, String) -> String
|
|
19
|
+
# private def same_file_target?: (String, String) -> bool
|
|
20
|
+
# private def normalize_grammar_path: (String) -> IR::Grammar
|
|
21
|
+
# private def record_generation_input: (String, String) -> GenerationInput
|
|
22
|
+
# private def select_configuration_mode: (String) -> void
|
|
23
|
+
# private def set_configuration_option: (Symbol, Object?) -> void
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
# @rbs (Array[String] arguments) -> Integer
|
|
28
|
+
def run_error_messages_command(arguments)
|
|
29
|
+
parser = error_messages_option_parser
|
|
30
|
+
remaining = parser.parse(arguments)
|
|
31
|
+
return print_help(parser) if @options[:help]
|
|
32
|
+
if @options[:messages_list] && @options[:messages_update]
|
|
33
|
+
raise Ibex::Error, "(cli):1:1: errors command accepts only one of --list or --update"
|
|
34
|
+
end
|
|
35
|
+
unless @options[:messages_list] || @options[:messages_update]
|
|
36
|
+
raise Ibex::Error, "(cli):1:1: errors command requires --list or --update[=FILE]"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
input = input_path(remaining)
|
|
40
|
+
automaton = automaton_for_error_messages(input)
|
|
41
|
+
if @options[:messages_list]
|
|
42
|
+
@stdout.write(ErrorMessages.render(automaton, **error_message_search_limits))
|
|
43
|
+
else
|
|
44
|
+
write_error_messages(automaton, input)
|
|
45
|
+
end
|
|
46
|
+
0
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @rbs () -> OptionParser
|
|
50
|
+
def error_messages_option_parser
|
|
51
|
+
OptionParser.new do |options|
|
|
52
|
+
options.banner = "Usage: ibex errors (--list | --update[=FILE]) [options] grammarfile"
|
|
53
|
+
options.on("--list", "list shortest error sentences on stdout") { @options[:messages_list] = true }
|
|
54
|
+
options.on("--update[=FILE]", "update messages (defaults to grammar.messages)") do |value|
|
|
55
|
+
@options[:messages_update] = value || true
|
|
56
|
+
end
|
|
57
|
+
options.on("--max-tokens=N", Integer, "maximum error-sentence token budget") do |value|
|
|
58
|
+
@options[:messages_max_tokens] = positive_messages_limit(value, "--max-tokens")
|
|
59
|
+
end
|
|
60
|
+
options.on("--max-configurations=N", Integer, "maximum error-sentence configuration budget") do |value|
|
|
61
|
+
@options[:messages_max_configurations] = positive_messages_limit(value, "--max-configurations")
|
|
62
|
+
end
|
|
63
|
+
options.on("--from=FORMAT", %w[grammar-ir automaton-ir], "resume from IR JSON") do |value|
|
|
64
|
+
@options[:from] = value
|
|
65
|
+
end
|
|
66
|
+
options.on("--mode=MODE", %w[default extended], "grammar mode") { |value| select_configuration_mode(value) }
|
|
67
|
+
options.on("--algorithm=NAME", %w[slr lalr ielr lr1], "parser construction algorithm") do |value|
|
|
68
|
+
set_configuration_option(:algorithm, value.to_sym)
|
|
69
|
+
@options[:messages_algorithm_explicit] = true
|
|
70
|
+
end
|
|
71
|
+
options.on("--warnings=CATEGORIES", "all, error, all,error, or none") do |value|
|
|
72
|
+
@options[:warnings] = warning_categories(value)
|
|
73
|
+
end
|
|
74
|
+
options.on("-S", "--output-status", "show pipeline status") { @options[:status] = true }
|
|
75
|
+
options.on("--help", "show help") { @options[:help] = true }
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# @rbs (String input_path) -> IR::Automaton
|
|
80
|
+
def automaton_for_error_messages(input_path)
|
|
81
|
+
return automaton_from_ir_for_messages(input_path) if @options[:from]
|
|
82
|
+
|
|
83
|
+
report_status("reading #{input_path}")
|
|
84
|
+
grammar = normalize_grammar_path(input_path)
|
|
85
|
+
grammar = activate_analysis_grammar(grammar)
|
|
86
|
+
handle_grammar_warnings(grammar, input_path)
|
|
87
|
+
build_automaton(grammar, input_path)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# @rbs (String input_path) -> IR::Automaton
|
|
91
|
+
def automaton_from_ir_for_messages(input_path)
|
|
92
|
+
report_status("reading #{input_path}")
|
|
93
|
+
value = IR::Validator.validate(File.read(input_path))
|
|
94
|
+
expected = @options[:from] == "grammar-ir" ? IR::Grammar : IR::Automaton
|
|
95
|
+
raise Ibex::Error, "#{input_path}:1:1: expected #{@options[:from]} input" unless value.is_a?(expected)
|
|
96
|
+
if value.is_a?(IR::Automaton) && @options[:messages_algorithm_explicit]
|
|
97
|
+
raise Ibex::Error, "(cli):1:1: --algorithm cannot be combined with --from=automaton-ir"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
grammar = if value.is_a?(IR::Grammar)
|
|
101
|
+
activate_analysis_grammar(value)
|
|
102
|
+
elsif value.is_a?(IR::Automaton)
|
|
103
|
+
value.grammar
|
|
104
|
+
else
|
|
105
|
+
raise Ibex::Error, "#{input_path}:1:1: expected #{@options[:from]} input"
|
|
106
|
+
end
|
|
107
|
+
handle_grammar_warnings(grammar, input_path)
|
|
108
|
+
return build_automaton(grammar, input_path) if value.is_a?(IR::Grammar)
|
|
109
|
+
|
|
110
|
+
if value.is_a?(IR::Automaton)
|
|
111
|
+
prepare_loaded_automaton(value, input_path)
|
|
112
|
+
return value
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
raise Ibex::Error, "#{input_path}:1:1: expected #{@options[:from]} input"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# @rbs (IR::Automaton automaton, String input_path) -> void
|
|
119
|
+
def write_error_messages(automaton, input_path)
|
|
120
|
+
configured = @options[:messages_update]
|
|
121
|
+
path = configured == true ? default_output_path(input_path, ".messages") : configured
|
|
122
|
+
raise Ibex::Error, "(cli):1:1: messages update path must not be empty" unless path.is_a?(String) && !path.empty?
|
|
123
|
+
if same_file_target?(path, input_path)
|
|
124
|
+
raise Ibex::Error, "(cli):1:1: messages update path must differ from the input path"
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
existing = if File.exist?(path)
|
|
128
|
+
ErrorMessages.load(path)
|
|
129
|
+
else
|
|
130
|
+
ErrorMessages::Document.new(entries: [])
|
|
131
|
+
end
|
|
132
|
+
update = ErrorMessages.update(automaton, existing: existing, **error_message_search_limits)
|
|
133
|
+
target_path = File.symlink?(path) ? File.realpath(path) : path
|
|
134
|
+
directory = File.dirname(File.expand_path(target_path))
|
|
135
|
+
Tempfile.create([".ibex-messages-", ".tmp"], directory, encoding: "UTF-8") do |file|
|
|
136
|
+
file.write(update.source)
|
|
137
|
+
File.chmod(messages_file_mode(target_path), file.path)
|
|
138
|
+
file.flush
|
|
139
|
+
file.fsync
|
|
140
|
+
File.rename(file.path, target_path)
|
|
141
|
+
end
|
|
142
|
+
write_error_message_update_report(update)
|
|
143
|
+
report_status("wrote #{path}")
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# @rbs () -> { max_tokens: Integer, max_configurations: Integer }
|
|
147
|
+
def error_message_search_limits
|
|
148
|
+
{
|
|
149
|
+
max_tokens: @options.fetch(:messages_max_tokens, ErrorMessages::SentenceSearch::DEFAULT_MAX_TOKENS),
|
|
150
|
+
max_configurations: @options.fetch(
|
|
151
|
+
:messages_max_configurations, ErrorMessages::SentenceSearch::DEFAULT_MAX_CONFIGURATIONS
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# @rbs (Integer value, String option) -> Integer
|
|
157
|
+
def positive_messages_limit(value, option)
|
|
158
|
+
return value if value.positive?
|
|
159
|
+
|
|
160
|
+
raise Ibex::Error, "(cli):1:1: #{option} must be positive"
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# @rbs (ErrorMessages::Update update) -> void
|
|
164
|
+
def write_error_message_update_report(update)
|
|
165
|
+
classifications = {
|
|
166
|
+
"uncovered" => update.uncovered, "unreachable" => update.unreachable, "moved" => update.moved
|
|
167
|
+
}
|
|
168
|
+
classifications.each do |label, items|
|
|
169
|
+
items.each { |item| @stdout.puts("#{label}: #{item}") }
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# @rbs (String path) -> Integer
|
|
174
|
+
def messages_file_mode(path)
|
|
175
|
+
return File.stat(path).mode & 0o777 if File.exist?(path)
|
|
176
|
+
|
|
177
|
+
0o666 & ~File.umask
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# @rbs!
|
|
181
|
+
# private def activate_analysis_grammar: (IR::Grammar, ?options: Hash[Symbol, Object?],
|
|
182
|
+
# ?explicit_keys: Array[Symbol]) -> IR::Grammar
|
|
183
|
+
end
|
|
184
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "optparse"
|
|
5
|
+
require_relative "../codegen/explain"
|
|
6
|
+
|
|
7
|
+
module Ibex
|
|
8
|
+
# Dedicated command-line view for selected parser conflicts.
|
|
9
|
+
module CLIExplain
|
|
10
|
+
# @rbs!
|
|
11
|
+
# private def print_help: (OptionParser) -> Integer
|
|
12
|
+
# private def input_path: (Array[String]) -> String
|
|
13
|
+
# private def positive_counterexample_limit: (Integer, String) -> Integer
|
|
14
|
+
# private def normalize_grammar_path: (String) -> IR::Grammar
|
|
15
|
+
# private def configuration_value: (String) -> untyped
|
|
16
|
+
# private def set_configuration_option: (Symbol, Object?) -> void
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
# @rbs (Array[String] arguments) -> Integer
|
|
21
|
+
def run_explain_command(arguments)
|
|
22
|
+
parser = explain_option_parser
|
|
23
|
+
remaining = parser.parse(arguments)
|
|
24
|
+
return print_help(parser) if @options[:help]
|
|
25
|
+
|
|
26
|
+
path = input_path(remaining)
|
|
27
|
+
grammar = activate_analysis_grammar(normalize_grammar_path(path))
|
|
28
|
+
automaton = LALR::Builder.new(
|
|
29
|
+
grammar, algorithm: configuration_value("parser.algorithm"),
|
|
30
|
+
entry_isolation: configuration_value("parser.entries") == :isolated
|
|
31
|
+
).build
|
|
32
|
+
explanation = Codegen::Explain.new(
|
|
33
|
+
automaton, state: @options[:explain_state], token: @options[:explain_token],
|
|
34
|
+
max_tokens: @options.fetch(:counterexample_max_tokens),
|
|
35
|
+
max_configurations: @options.fetch(:counterexample_max_configurations)
|
|
36
|
+
)
|
|
37
|
+
output = @options[:explain_format] == "json" ? JSON.pretty_generate(explanation.to_h) : explanation.render_text
|
|
38
|
+
@stdout.puts(output)
|
|
39
|
+
0
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @rbs () -> OptionParser
|
|
43
|
+
def explain_option_parser
|
|
44
|
+
OptionParser.new do |options|
|
|
45
|
+
options.banner = "Usage: ibex explain [options] grammarfile"
|
|
46
|
+
options.on("--state=N", Integer, "select one automaton state") { |value| @options[:explain_state] = value }
|
|
47
|
+
options.on("--token=NAME", "select a grammar token name or exact display name") do |value|
|
|
48
|
+
@options[:explain_token] = value
|
|
49
|
+
end
|
|
50
|
+
options.on("--format=FORMAT", %w[text json], "text or json (default: text)") do |value|
|
|
51
|
+
@options[:explain_format] = value
|
|
52
|
+
end
|
|
53
|
+
options.on("--algorithm=NAME", %w[slr lalr ielr lr1], "parser construction algorithm") do |value|
|
|
54
|
+
set_configuration_option(:algorithm, value.to_sym)
|
|
55
|
+
end
|
|
56
|
+
options.on("--entry-isolation", "build independent state sets for each start symbol") do
|
|
57
|
+
set_configuration_option(:entry_isolation, true)
|
|
58
|
+
end
|
|
59
|
+
options.on("--mode=MODE", %w[default extended], "grammar mode") do |value|
|
|
60
|
+
set_configuration_option(:mode, value.to_sym)
|
|
61
|
+
end
|
|
62
|
+
add_explain_search_options(options)
|
|
63
|
+
options.on("--help", "show help") { @options[:help] = true }
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @rbs (OptionParser options) -> void
|
|
68
|
+
def add_explain_search_options(options)
|
|
69
|
+
options.on("--counterexample-max-tokens=N", Integer, "maximum counterexample search token budget") do |value|
|
|
70
|
+
@options[:counterexample_max_tokens] = positive_counterexample_limit(value, "--counterexample-max-tokens")
|
|
71
|
+
end
|
|
72
|
+
options.on(
|
|
73
|
+
"--counterexample-max-configurations=N", Integer, "maximum counterexample search configuration budget"
|
|
74
|
+
) do |value|
|
|
75
|
+
@options[:counterexample_max_configurations] = positive_counterexample_limit(
|
|
76
|
+
value, "--counterexample-max-configurations"
|
|
77
|
+
)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# @rbs!
|
|
82
|
+
# private def activate_analysis_grammar: (IR::Grammar, ?options: Hash[Symbol, Object?],
|
|
83
|
+
# ?explicit_keys: Array[Symbol]) -> IR::Grammar
|
|
84
|
+
end
|
|
85
|
+
end
|