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
data/lib/ibex/cli.rb
CHANGED
|
@@ -1,39 +1,112 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
2
3
|
|
|
4
|
+
require "json"
|
|
3
5
|
require "optparse"
|
|
4
|
-
require_relative "
|
|
6
|
+
require_relative "version"
|
|
7
|
+
require_relative "error"
|
|
8
|
+
require_relative "configuration"
|
|
9
|
+
require_relative "messages"
|
|
10
|
+
require_relative "artifact_set"
|
|
11
|
+
require_relative "generation_input"
|
|
12
|
+
require_relative "generation_transaction"
|
|
13
|
+
require_relative "frontend/generation"
|
|
14
|
+
require_relative "ir/grammar_ir"
|
|
15
|
+
require_relative "ir/lexer_ir"
|
|
16
|
+
require_relative "ir/serialize"
|
|
17
|
+
require_relative "ir/automaton_ir"
|
|
18
|
+
require_relative "normalize"
|
|
19
|
+
require_relative "analysis"
|
|
20
|
+
require_relative "lalr/conflict"
|
|
21
|
+
require_relative "lalr/on_error_reductions"
|
|
22
|
+
require_relative "lalr/default_reductions"
|
|
23
|
+
require_relative "lalr/build_metrics"
|
|
24
|
+
require_relative "lalr/inadequacy_report"
|
|
25
|
+
require_relative "lalr/direct_lookaheads"
|
|
26
|
+
require_relative "lalr/ielr_partition"
|
|
27
|
+
require_relative "lalr/builder"
|
|
28
|
+
require_relative "codegen/ruby"
|
|
5
29
|
require_relative "cli/counterexample_options"
|
|
30
|
+
require_relative "cli/generation_error_messages"
|
|
31
|
+
require_relative "cli/generation_artifacts"
|
|
6
32
|
require_relative "cli/outputs"
|
|
7
33
|
|
|
8
34
|
module Ibex
|
|
35
|
+
CLI_FEATURE_ROOT = File.expand_path("cli", __dir__ || raise("CLI source directory is unavailable")) #: String
|
|
36
|
+
autoload :CLIAmbiguity, File.join(CLI_FEATURE_ROOT, "ambiguity")
|
|
37
|
+
autoload :CLIAnalysis, File.join(CLI_FEATURE_ROOT, "analysis")
|
|
38
|
+
autoload :CLIBisonImport, File.join(CLI_FEATURE_ROOT, "bison_import")
|
|
39
|
+
autoload :CLICoverage, File.join(CLI_FEATURE_ROOT, "coverage")
|
|
40
|
+
autoload :CLIDebug, File.join(CLI_FEATURE_ROOT, "debug")
|
|
41
|
+
autoload :CLIDiagnostics, File.join(CLI_FEATURE_ROOT, "diagnostics")
|
|
42
|
+
autoload :CLIDocumentation, File.join(CLI_FEATURE_ROOT, "documentation")
|
|
43
|
+
autoload :CLIErrorMessages, File.join(CLI_FEATURE_ROOT, "error_messages")
|
|
44
|
+
autoload :CLIEquiv, File.join(CLI_FEATURE_ROOT, "equiv")
|
|
45
|
+
autoload :CLIExplain, File.join(CLI_FEATURE_ROOT, "explain")
|
|
46
|
+
autoload :CLIFormatting, File.join(CLI_FEATURE_ROOT, "formatting")
|
|
47
|
+
autoload :CLIFix, File.join(CLI_FEATURE_ROOT, "fix")
|
|
48
|
+
autoload :CLIFuzz, File.join(CLI_FEATURE_ROOT, "fuzz")
|
|
49
|
+
autoload :CLIGrammarTests, File.join(CLI_FEATURE_ROOT, "grammar_tests")
|
|
50
|
+
autoload :CLIIRTools, File.join(CLI_FEATURE_ROOT, "ir_tools")
|
|
51
|
+
autoload :CLILSP, File.join(CLI_FEATURE_ROOT, "lsp")
|
|
52
|
+
autoload :CLIRaccMigration, File.join(CLI_FEATURE_ROOT, "racc_migration")
|
|
53
|
+
autoload :CLIReduce, File.join(CLI_FEATURE_ROOT, "reduce")
|
|
54
|
+
autoload :CLISamples, File.join(CLI_FEATURE_ROOT, "samples")
|
|
55
|
+
autoload :CLIVerify, File.join(CLI_FEATURE_ROOT, "verify")
|
|
56
|
+
autoload :CLIWatch, File.join(CLI_FEATURE_ROOT, "watch")
|
|
57
|
+
|
|
9
58
|
# @rbs!
|
|
10
59
|
# interface _CLIOutput
|
|
11
|
-
# def puts: (*
|
|
12
|
-
# def write: (String) ->
|
|
60
|
+
# def puts: (*Object?) -> Object?
|
|
61
|
+
# def write: (String) -> Object?
|
|
62
|
+
# end
|
|
63
|
+
# interface _CLIInput
|
|
64
|
+
# def read: () -> String
|
|
65
|
+
# def gets: () -> String?
|
|
13
66
|
# end
|
|
14
67
|
# type cli_options = {
|
|
15
68
|
# emit: String,
|
|
16
69
|
# mode: Symbol,
|
|
17
70
|
# table: Symbol,
|
|
71
|
+
# ?cst_trivia: Symbol,
|
|
18
72
|
# line_convert: bool,
|
|
19
73
|
# ?line_convert_all: bool,
|
|
20
74
|
# counterexample_max_tokens: Integer,
|
|
21
75
|
# counterexample_max_configurations: Integer,
|
|
22
76
|
# ?from: String,
|
|
23
77
|
# ?algorithm: Symbol,
|
|
78
|
+
# ?suggest_ielr: bool,
|
|
79
|
+
# ?entry_isolation: bool,
|
|
80
|
+
# ?ielr_strategy: Symbol,
|
|
81
|
+
# ?ielr_report: bool,
|
|
82
|
+
# ?remove_unreachable: bool,
|
|
24
83
|
# ?warnings: Array[Symbol],
|
|
25
84
|
# ?output: String,
|
|
26
85
|
# ?embedded: bool,
|
|
27
86
|
# ?debug: bool,
|
|
28
87
|
# ?verbose: bool,
|
|
29
88
|
# ?rbs: String | true,
|
|
89
|
+
# ?action_source: String | true,
|
|
90
|
+
# ?manifest: String | true,
|
|
91
|
+
# ?watch: bool,
|
|
30
92
|
# ?dot: String,
|
|
93
|
+
# ?mermaid: String,
|
|
31
94
|
# ?html: String,
|
|
95
|
+
# ?railroad: String,
|
|
96
|
+
# ?messages: String,
|
|
97
|
+
# ?messages_update: String | true,
|
|
98
|
+
# ?messages_algorithm_explicit: bool,
|
|
99
|
+
# ?sample_count: Integer,
|
|
100
|
+
# ?sample_seed: Integer,
|
|
101
|
+
# ?sample_max_tokens: Integer,
|
|
102
|
+
# ?sample_max_depth: Integer,
|
|
103
|
+
# ?sample_max_expansions: Integer,
|
|
32
104
|
# ?log_file: String,
|
|
33
105
|
# ?executable: String,
|
|
34
106
|
# ?frozen: bool,
|
|
35
107
|
# ?omit_actions: bool,
|
|
36
108
|
# ?superclass: String,
|
|
109
|
+
# ?verify_output: bool,
|
|
37
110
|
# ?check_only: bool,
|
|
38
111
|
# ?status: bool,
|
|
39
112
|
# ?profile: bool,
|
|
@@ -41,111 +114,394 @@ module Ibex
|
|
|
41
114
|
# ?version: bool,
|
|
42
115
|
# ?runtime_version: bool,
|
|
43
116
|
# ?copyright: bool,
|
|
44
|
-
# ?help: bool
|
|
117
|
+
# ?help: bool,
|
|
118
|
+
# ?explain_state: Integer,
|
|
119
|
+
# ?explain_token: String,
|
|
120
|
+
# ?explain_format: String,
|
|
121
|
+
# ?check_ambiguity: bool,
|
|
122
|
+
# ?check_format: String,
|
|
123
|
+
# ?fuzz_seed: Integer,
|
|
124
|
+
# ?fuzz_count: Integer,
|
|
125
|
+
# ?fuzz_max_tokens: Integer,
|
|
126
|
+
# ?fuzz_max_depth: Integer,
|
|
127
|
+
# ?fuzz_max_expansions: Integer,
|
|
128
|
+
# ?fuzz_max_actions: Integer,
|
|
129
|
+
# ?fuzz_max_stack: Integer,
|
|
130
|
+
# ?fuzz_coverage_guided: bool,
|
|
131
|
+
# ?fuzz_path_length: Integer,
|
|
132
|
+
# ?fuzz_against: String,
|
|
133
|
+
# ?fuzz_against_runtime: String,
|
|
134
|
+
# ?fuzz_against_timeout: Integer,
|
|
135
|
+
# ?fuzz_against_max_output: Integer,
|
|
136
|
+
# ?fuzz_max_reduction_trials: Integer,
|
|
137
|
+
# ?fuzz_regression_dir: String,
|
|
138
|
+
# ?fuzz_save_regression: bool,
|
|
139
|
+
# ?fuzz_format: String,
|
|
140
|
+
# ?reduce_command: String,
|
|
141
|
+
# ?reduce_mode: Symbol,
|
|
142
|
+
# ?reduce_max_trials: Integer,
|
|
143
|
+
# ?reduce_timeout: Integer,
|
|
144
|
+
# ?reduce_max_output_bytes: Integer,
|
|
145
|
+
# ?reduce_max_input_bytes: Integer,
|
|
146
|
+
# ?reduce_format: String
|
|
45
147
|
# }
|
|
46
148
|
|
|
47
149
|
# Command-line pipeline coordinator.
|
|
48
150
|
# rubocop:disable Metrics/ClassLength -- inline type contracts add lines without adding runtime responsibilities.
|
|
49
151
|
class CLI
|
|
152
|
+
SUBCOMMAND_HANDLERS = {
|
|
153
|
+
"check" => %i[CLIAmbiguity run_check_command],
|
|
154
|
+
"diff" => %i[CLIAnalysis run_diff_command],
|
|
155
|
+
"diagnose" => %i[CLIDiagnostics run_diagnose_command],
|
|
156
|
+
"coverage" => %i[CLICoverage run_coverage_command], "config" => %i[CLIConfig run_config_command],
|
|
157
|
+
"debug" => %i[CLIDebug run_debug_command],
|
|
158
|
+
"doc" => %i[CLIDocumentation run_documentation_command],
|
|
159
|
+
"errors" => %i[CLIErrorMessages run_error_messages_command],
|
|
160
|
+
"equiv" => %i[CLIEquiv run_equiv_command],
|
|
161
|
+
"explain" => %i[CLIExplain run_explain_command],
|
|
162
|
+
"fmt" => %i[CLIFormatting run_format_command],
|
|
163
|
+
"fix" => %i[CLIFix run_fix_command],
|
|
164
|
+
"fuzz" => %i[CLIFuzz run_fuzz_command],
|
|
165
|
+
"test" => %i[CLIGrammarTests run_grammar_tests_command],
|
|
166
|
+
"lsp" => %i[CLILSP run_lsp_command],
|
|
167
|
+
"import" => %i[CLIBisonImport run_bison_import_command],
|
|
168
|
+
"metrics" => %i[CLIAnalysis run_metrics_command],
|
|
169
|
+
"migrate-check" => %i[CLIRaccMigration run_migrate_check_command],
|
|
170
|
+
"migrate-harness" => %i[CLIRaccMigration run_migrate_harness_command],
|
|
171
|
+
"reduce" => %i[CLIReduce run_reduce_command],
|
|
172
|
+
"samples" => %i[CLISamples run_samples_command],
|
|
173
|
+
"verify" => %i[CLIVerify run_verify_command],
|
|
174
|
+
"validate-ir" => %i[CLIIRTools run_validate_ir_command],
|
|
175
|
+
"compare" => %i[CLIIRTools run_compare_command]
|
|
176
|
+
}.freeze #: Hash[String, [Symbol, Symbol]]
|
|
177
|
+
|
|
50
178
|
include CLICounterexampleOptions
|
|
179
|
+
include CLIGenerationErrorMessages
|
|
180
|
+
include CLIGenerationArtifacts
|
|
51
181
|
include CLIOutputs
|
|
52
182
|
|
|
53
183
|
# @rbs @stdout: _CLIOutput
|
|
54
184
|
# @rbs @stderr: _CLIOutput
|
|
55
185
|
# @rbs @options: cli_options
|
|
186
|
+
# @rbs @language: String
|
|
187
|
+
# @rbs @configuration_explicit_options: Hash[Symbol, bool]
|
|
188
|
+
# @rbs @generation_grammar: IR::Grammar?
|
|
189
|
+
# @rbs @generation_automaton: IR::Automaton?
|
|
56
190
|
|
|
57
|
-
#
|
|
58
|
-
|
|
59
|
-
|
|
191
|
+
# rubocop:disable Layout/LineLength
|
|
192
|
+
# @rbs (Array[String] arguments, ?stdin: _CLIInput, ?stdout: _CLIOutput, ?stderr: _CLIOutput, ?watch_clock: (^() -> Float)?, ?watch_sleeper: (^(Float) -> void)?, ?watch_iteration_hook: (^(Symbol, Integer, Array[String]) -> (Integer | Symbol | nil))?) -> Integer
|
|
193
|
+
def self.start(arguments, stdin: $stdin, stdout: $stdout, stderr: $stderr, watch_clock: nil, watch_sleeper: nil,
|
|
194
|
+
watch_iteration_hook: nil)
|
|
195
|
+
new(
|
|
196
|
+
stdin: stdin, stdout: stdout, stderr: stderr, watch_clock: watch_clock,
|
|
197
|
+
watch_sleeper: watch_sleeper, watch_iteration_hook: watch_iteration_hook
|
|
198
|
+
).run(arguments)
|
|
60
199
|
end
|
|
61
200
|
|
|
62
|
-
# @rbs (stdout: _CLIOutput, stderr: _CLIOutput) -> void
|
|
63
|
-
def initialize(stdout:, stderr:)
|
|
201
|
+
# @rbs (?stdin: _CLIInput, stdout: _CLIOutput, stderr: _CLIOutput, ?watch_clock: (^() -> Float)?, ?watch_sleeper: (^(Float) -> void)?, ?watch_iteration_hook: (^(Symbol, Integer, Array[String]) -> (Integer | Symbol | nil))?) -> void
|
|
202
|
+
def initialize(stdout:, stderr:, stdin: $stdin, watch_clock: nil, watch_sleeper: nil, watch_iteration_hook: nil)
|
|
203
|
+
@stdin = stdin
|
|
64
204
|
@stdout = stdout
|
|
65
205
|
@stderr = stderr
|
|
66
|
-
@
|
|
206
|
+
@watch_clock = watch_clock || -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) }
|
|
207
|
+
@watch_sleeper = watch_sleeper || ->(seconds) { sleep(seconds) }
|
|
208
|
+
@watch_iteration_hook = watch_iteration_hook || ->(_event, _iteration, _paths) {}
|
|
209
|
+
@language = Messages.language(ENV.fetch("IBEX_LANG", nil))
|
|
210
|
+
@options = {
|
|
211
|
+
emit: "ruby", mode: Configuration::Registry.fetch("grammar.mode").default,
|
|
212
|
+
table: Configuration::Registry.fetch("table.representation").default, line_convert: true
|
|
213
|
+
}
|
|
67
214
|
.merge(CLICounterexampleOptions::DEFAULTS)
|
|
215
|
+
@configuration_explicit_options = {}
|
|
216
|
+
@generation_grammar = nil
|
|
217
|
+
@generation_automaton = @analysis_configuration = nil
|
|
68
218
|
end
|
|
219
|
+
# rubocop:enable Layout/LineLength
|
|
69
220
|
|
|
70
221
|
# @rbs (Array[String] arguments) -> Integer
|
|
71
222
|
def run(arguments)
|
|
223
|
+
arguments = extract_language(arguments)
|
|
224
|
+
@generation_grammar = nil
|
|
225
|
+
@generation_automaton = @analysis_configuration = nil
|
|
226
|
+
subcommand = dispatch_subcommand(arguments)
|
|
227
|
+
return subcommand unless subcommand.nil?
|
|
228
|
+
|
|
72
229
|
parser = option_parser
|
|
73
230
|
remaining = parser.parse(arguments)
|
|
231
|
+
validate_watch_information_options
|
|
74
232
|
information = informational_result(parser)
|
|
75
233
|
return information unless information.nil?
|
|
76
234
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
235
|
+
validate_messages_options
|
|
236
|
+
validate_generation_options
|
|
237
|
+
path = input_path(remaining)
|
|
238
|
+
validate_generation_paths!(path)
|
|
239
|
+
if @options[:watch]
|
|
240
|
+
run_watch_feature(path)
|
|
241
|
+
else
|
|
242
|
+
process_grammar(path)
|
|
243
|
+
end
|
|
244
|
+
rescue OptionParser::ParseError, Ibex::Error, SystemCallError, SystemStackError => e
|
|
245
|
+
@stderr.puts(Messages.translate("cli.error", language: @language, detail: e.message))
|
|
80
246
|
1
|
|
81
247
|
end
|
|
82
248
|
|
|
83
249
|
private
|
|
84
250
|
|
|
251
|
+
# @rbs (Symbol name) -> void
|
|
252
|
+
def mark_configuration_option(name)
|
|
253
|
+
@configuration_explicit_options[name] = true
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# OptionParser accepts a heterogeneous set of operation and configuration
|
|
257
|
+
# values. The CLIAdapter is the validation boundary for this dynamic map.
|
|
258
|
+
# @rbs (Symbol name, untyped value) -> void
|
|
259
|
+
def set_configuration_option(name, value)
|
|
260
|
+
@options[name] = value
|
|
261
|
+
mark_configuration_option(name)
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# @rbs (String value) -> void
|
|
265
|
+
def select_configuration_mode(value)
|
|
266
|
+
set_configuration_option(:mode, value.to_sym)
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# @rbs () -> Configuration::Resolver
|
|
270
|
+
def effective_configuration
|
|
271
|
+
grammar = @generation_grammar
|
|
272
|
+
contract = grammar&.parser_contract
|
|
273
|
+
@analysis_configuration || Configuration::CLIAdapter.new(
|
|
274
|
+
@options, explicit_keys: @configuration_explicit_options.keys
|
|
275
|
+
).resolve(
|
|
276
|
+
grammar: contract&.configuration_values || {},
|
|
277
|
+
locations: contract&.configuration_locations || {}
|
|
278
|
+
)
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Resolve a command-local legacy option hash without promoting it into the
|
|
282
|
+
# reusable CLI instance's generation settings.
|
|
283
|
+
# @rbs (Hash[Symbol, untyped] options, explicit_keys: Array[Symbol]) -> Configuration::Resolver
|
|
284
|
+
def resolve_configuration_options(options, explicit_keys:)
|
|
285
|
+
Configuration::CLIAdapter.new(options, explicit_keys: explicit_keys).resolve
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# @rbs (Hash[Symbol, untyped] options, String name) -> untyped
|
|
289
|
+
def local_configuration_value(options, name)
|
|
290
|
+
explicit_keys = options.fetch(:configuration_explicit)
|
|
291
|
+
resolve_configuration_options(options, explicit_keys: explicit_keys).value(name)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# @rbs (Hash[Symbol, untyped] options, Symbol name, untyped value) -> void
|
|
295
|
+
def set_local_configuration_option(options, name, value)
|
|
296
|
+
options[name] = value
|
|
297
|
+
options.fetch(:configuration_explicit) << name
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Configuration values have already been validated by Configuration::Resolver;
|
|
301
|
+
# callers narrow the value according to the option they are consuming.
|
|
302
|
+
# @rbs (String name) -> untyped
|
|
303
|
+
def configuration_value(name)
|
|
304
|
+
effective_configuration.value(name)
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# @rbs (Array[String] arguments) -> Array[String]
|
|
308
|
+
def extract_language(arguments)
|
|
309
|
+
remaining = [] #: Array[String]
|
|
310
|
+
index = 0
|
|
311
|
+
while index < arguments.length
|
|
312
|
+
argument = arguments.fetch(index)
|
|
313
|
+
if argument == "--lang"
|
|
314
|
+
value = arguments[index + 1]
|
|
315
|
+
raise OptionParser::MissingArgument, "--lang" unless value
|
|
316
|
+
|
|
317
|
+
@language = Messages.language(value)
|
|
318
|
+
index += 2
|
|
319
|
+
elsif argument.start_with?("--lang=")
|
|
320
|
+
value = argument.delete_prefix("--lang=")
|
|
321
|
+
raise OptionParser::MissingArgument, "--lang" if value.empty?
|
|
322
|
+
|
|
323
|
+
@language = Messages.language(value)
|
|
324
|
+
index += 1
|
|
325
|
+
else
|
|
326
|
+
remaining << argument
|
|
327
|
+
index += 1
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
remaining
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# @rbs (Array[String] arguments) -> Integer?
|
|
334
|
+
def dispatch_subcommand(arguments)
|
|
335
|
+
definition = SUBCOMMAND_HANDLERS[arguments.first]
|
|
336
|
+
return unless definition
|
|
337
|
+
|
|
338
|
+
feature, handler = definition
|
|
339
|
+
activate_cli_feature(feature)
|
|
340
|
+
send(handler, arguments.drop(1))
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# @rbs (Symbol feature) -> void
|
|
344
|
+
def activate_cli_feature(feature)
|
|
345
|
+
extension = Ibex.const_get(feature)
|
|
346
|
+
extend extension unless singleton_class.ancestors.include?(extension)
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# @rbs (String path) -> Integer
|
|
350
|
+
def run_watch_feature(path)
|
|
351
|
+
activate_cli_feature(:CLIWatch)
|
|
352
|
+
send(:run_watch, path)
|
|
353
|
+
end
|
|
354
|
+
|
|
85
355
|
# @rbs () -> OptionParser
|
|
86
356
|
def option_parser
|
|
87
357
|
OptionParser.new do |options|
|
|
88
358
|
options.banner = "Usage: ibex [options] grammarfile"
|
|
89
359
|
add_pipeline_options(options)
|
|
90
360
|
add_output_options(options)
|
|
361
|
+
add_error_messages_generation_option(options)
|
|
91
362
|
add_compatibility_options(options)
|
|
92
363
|
add_information_options(options)
|
|
364
|
+
add_subcommand_help(options)
|
|
93
365
|
end
|
|
94
366
|
end
|
|
95
367
|
|
|
96
368
|
# @rbs (OptionParser options) -> void
|
|
369
|
+
def add_subcommand_help(options)
|
|
370
|
+
options.separator("")
|
|
371
|
+
options.separator("Subcommands:")
|
|
372
|
+
options.separator(" check --ambiguity search for ambiguity within explicit budgets")
|
|
373
|
+
options.separator(CONFIG_SUBCOMMAND_HELP)
|
|
374
|
+
options.separator(" debug AUTOMATON [TOKEN] simulate validated Automaton IR tables")
|
|
375
|
+
options.separator(" diagnose collect frontend diagnostics")
|
|
376
|
+
options.separator(" diff OLD NEW classify grammar and automaton changes")
|
|
377
|
+
options.separator(" doc render grammar documentation")
|
|
378
|
+
options.separator(" errors --list|--update list or update example-keyed syntax error messages")
|
|
379
|
+
options.separator(" equiv LEFT RIGHT search for bounded language differences")
|
|
380
|
+
options.separator(" explain explain selected parser conflicts")
|
|
381
|
+
options.separator(" fmt format grammar source")
|
|
382
|
+
options.separator(" fix propose bounded-equivalent conflict repairs")
|
|
383
|
+
options.separator(" fuzz run bounded grammar-derived differential fuzzing")
|
|
384
|
+
options.separator(" test run grammar-declared source examples")
|
|
385
|
+
options.separator(" lsp run the language server over stdio")
|
|
386
|
+
options.separator(" import bison FILE import Bison grammar structure for analysis")
|
|
387
|
+
options.separator(" migrate-check statically check a racc grammar migration")
|
|
388
|
+
options.separator(" migrate-harness generate a differential subprocess harness")
|
|
389
|
+
options.separator(" metrics GRAMMAR report deterministic grammar/table metrics")
|
|
390
|
+
options.separator(" reduce delta-debug a failing token, line, or byte sequence")
|
|
391
|
+
options.separator(" samples generate bounded terminal sentences")
|
|
392
|
+
options.separator(" verify AUTOMATON independently verify Automaton IR semantics")
|
|
393
|
+
options.separator(" validate-ir FILE validate the current IR document")
|
|
394
|
+
options.separator(" compare BEFORE AFTER compare current IR documents")
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
# @rbs (OptionParser options) -> void
|
|
398
|
+
# rubocop:disable Metrics/MethodLength -- pipeline flags share one parser boundary.
|
|
97
399
|
def add_pipeline_options(options)
|
|
98
|
-
options.on("--emit=FORMAT", "ast, grammar-ir, automaton-ir, or ruby")
|
|
400
|
+
options.on("--emit=FORMAT", "ast, sets, lexer-ir, grammar-ir, automaton-ir, or ruby") do |value|
|
|
401
|
+
@options[:emit] = value
|
|
402
|
+
end
|
|
99
403
|
options.on("--from=FORMAT", %w[grammar-ir automaton-ir], "resume from IR JSON") do |value|
|
|
100
404
|
@options[:from] = value
|
|
101
405
|
end
|
|
102
|
-
options.on("--mode=MODE", %w[
|
|
406
|
+
options.on("--mode=MODE", %w[default extended], "grammar mode") { |value| select_configuration_mode(value) }
|
|
103
407
|
options.on("--table=FORMAT", %w[plain compact], "parser table format") do |value|
|
|
104
|
-
|
|
408
|
+
set_configuration_option(:table, value.to_sym)
|
|
409
|
+
end
|
|
410
|
+
options.on(
|
|
411
|
+
"--cst-trivia=POLICY",
|
|
412
|
+
%w[leading balanced drop attach],
|
|
413
|
+
"leading, balanced, drop, or attach (alias for leading)"
|
|
414
|
+
) do |value|
|
|
415
|
+
set_configuration_option(:cst_trivia, value.to_sym)
|
|
416
|
+
end
|
|
417
|
+
options.on("--algorithm=NAME", %w[slr lalr ielr lr1], "parser construction algorithm") do |value|
|
|
418
|
+
set_configuration_option(:algorithm, value.to_sym)
|
|
419
|
+
end
|
|
420
|
+
options.on("--ielr-strategy=NAME", %w[direct partition], "IELR construction strategy") do |value|
|
|
421
|
+
@options[:ielr_strategy] = value.to_sym
|
|
422
|
+
end
|
|
423
|
+
options.on("--ielr-report", "report canonical-vs-IELR action differences") do
|
|
424
|
+
@options[:ielr_report] = true
|
|
425
|
+
end
|
|
426
|
+
options.on("--remove-unreachable", "compact unreachable IELR states after resolution") do
|
|
427
|
+
@options[:remove_unreachable] = true
|
|
428
|
+
end
|
|
429
|
+
options.on("--suggest-ielr", "check whether IELR removes unexpected LALR conflicts") do
|
|
430
|
+
@options[:suggest_ielr] = true
|
|
105
431
|
end
|
|
106
|
-
options.on("--
|
|
107
|
-
|
|
432
|
+
options.on("--entry-isolation", "build independent state sets for each start symbol") do
|
|
433
|
+
set_configuration_option(:entry_isolation, true)
|
|
108
434
|
end
|
|
109
435
|
options.on("--warnings=CATEGORIES", "all, error, all,error, or none") do |value|
|
|
110
436
|
@options[:warnings] = warning_categories(value)
|
|
111
437
|
end
|
|
438
|
+
options.on("--watch", "regenerate file outputs when grammar sources change") { @options[:watch] = true }
|
|
112
439
|
end
|
|
440
|
+
# rubocop:enable Metrics/MethodLength
|
|
113
441
|
|
|
114
442
|
# @rbs (OptionParser options) -> void
|
|
115
443
|
def add_output_options(options)
|
|
116
444
|
options.on("-o", "--output-file=FILE", "generated parser path") { |value| @options[:output] = value }
|
|
117
|
-
options.on("-E", "--embedded", "embed the Pure Ruby runtime")
|
|
118
|
-
|
|
119
|
-
|
|
445
|
+
options.on("-E", "--embedded", "embed the Pure Ruby runtime") do
|
|
446
|
+
set_configuration_option(:embedded, true)
|
|
447
|
+
end
|
|
448
|
+
options.on("-t", "--debug", "generate a debug-capable parser") do
|
|
449
|
+
set_configuration_option(:debug, true)
|
|
450
|
+
end
|
|
451
|
+
options.on("-g", "obsolete alias for --debug") do
|
|
452
|
+
set_configuration_option(:debug, true)
|
|
453
|
+
end
|
|
120
454
|
options.on("-v", "--verbose", "write an automaton report") { @options[:verbose] = true }
|
|
121
455
|
add_counterexample_options(options)
|
|
122
|
-
options
|
|
123
|
-
|
|
456
|
+
add_signature_output_options(options)
|
|
457
|
+
options.on("--manifest[=FILE]", "write a generation manifest (defaults beside parser)") do |value|
|
|
458
|
+
@options[:manifest] = value || true
|
|
124
459
|
end
|
|
125
460
|
options.on("--dot=FILE", "write Graphviz DOT") { |value| @options[:dot] = value }
|
|
461
|
+
options.on("--mermaid=FILE", "write a Mermaid flowchart") { |value| @options[:mermaid] = value }
|
|
126
462
|
options.on("--html=FILE", "write a self-contained HTML report") { |value| @options[:html] = value }
|
|
463
|
+
options.on("--railroad=FILE", "write a self-contained SVG railroad diagram") do |value|
|
|
464
|
+
@options[:railroad] = value
|
|
465
|
+
end
|
|
127
466
|
options.on("-O", "--log-file=FILE", "automaton report path") do |value|
|
|
128
467
|
@options[:verbose] = true
|
|
129
468
|
@options[:log_file] = value
|
|
130
469
|
end
|
|
131
470
|
options.on("-e", "--executable [RUBY]", "add a shebang") do |value|
|
|
132
|
-
|
|
471
|
+
set_configuration_option(:executable, value || "/usr/bin/env ruby")
|
|
472
|
+
end
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
# @rbs (OptionParser options) -> void
|
|
476
|
+
def add_signature_output_options(options)
|
|
477
|
+
options.on("--rbs[=FILE]", "write an RBS signature (defaults beside parser)") do |value|
|
|
478
|
+
@options[:rbs] = value || true
|
|
479
|
+
end
|
|
480
|
+
options.on("--action-source[=FILE]", "write static-check-only action Ruby (defaults beside parser)") do |value|
|
|
481
|
+
@options[:action_source] = value || true
|
|
133
482
|
end
|
|
134
483
|
end
|
|
135
484
|
|
|
136
485
|
# @rbs (OptionParser options) -> void
|
|
137
486
|
def add_compatibility_options(options)
|
|
138
|
-
options.on("-F", "--frozen", "emit frozen string literals")
|
|
487
|
+
options.on("-F", "--frozen", "emit frozen string literals") do
|
|
488
|
+
set_configuration_option(:frozen, true)
|
|
489
|
+
end
|
|
139
490
|
options.on("--line-convert-all", "convert all source lines") do
|
|
140
|
-
@options[:line_convert] = true
|
|
141
491
|
@options[:line_convert_all] = true
|
|
492
|
+
set_configuration_option(:line_convert, true)
|
|
142
493
|
end
|
|
143
494
|
options.on("-l", "--no-line-convert", "use generated-file action lines") do
|
|
144
|
-
@options[:line_convert] = false
|
|
145
495
|
@options[:line_convert_all] = false
|
|
496
|
+
set_configuration_option(:line_convert, false)
|
|
146
497
|
end
|
|
147
|
-
options.on("-a", "--no-omit-actions", "generate implicit action methods")
|
|
148
|
-
|
|
498
|
+
options.on("-a", "--no-omit-actions", "generate implicit action methods") do
|
|
499
|
+
set_configuration_option(:omit_actions, false)
|
|
500
|
+
end
|
|
501
|
+
options.on("--superclass=CLASS", "override parser superclass") do |value|
|
|
502
|
+
set_configuration_option(:superclass, value)
|
|
503
|
+
end
|
|
504
|
+
options.on("--check", "verify generated parser content without rewriting") { @options[:verify_output] = true }
|
|
149
505
|
options.on("-C", "--check-only", "check grammar and exit") { @options[:check_only] = true }
|
|
150
506
|
options.on("-S", "--output-status", "show pipeline status") { @options[:status] = true }
|
|
151
507
|
options.on("-P", "accept the compatibility profiling flag") { @options[:profile] = true }
|
|
@@ -154,12 +510,55 @@ module Ibex
|
|
|
154
510
|
|
|
155
511
|
# @rbs (OptionParser options) -> void
|
|
156
512
|
def add_information_options(options)
|
|
513
|
+
options.on("--lang=LANG", "built-in diagnostic language (en or ja)") do |value|
|
|
514
|
+
@language = Messages.language(value)
|
|
515
|
+
end
|
|
157
516
|
options.on("--version", "show version") { @options[:version] = true }
|
|
158
517
|
options.on("--runtime-version", "show runtime version") { @options[:runtime_version] = true }
|
|
159
518
|
options.on("--copyright", "show copyright") { @options[:copyright] = true }
|
|
160
519
|
options.on("--help", "show help") { @options[:help] = true }
|
|
161
520
|
end
|
|
162
521
|
|
|
522
|
+
# @rbs @analysis_configuration: Configuration::Resolver?
|
|
523
|
+
|
|
524
|
+
# @rbs (IR::Grammar grammar, ?options: Hash[Symbol, untyped], ?explicit_keys: Array[Symbol]) -> IR::Grammar
|
|
525
|
+
def activate_analysis_grammar(grammar, options: @options, explicit_keys: @configuration_explicit_options.keys)
|
|
526
|
+
adapter = Configuration::CLIAdapter.new(options, explicit_keys: explicit_keys)
|
|
527
|
+
cli = adapter.configuration_values
|
|
528
|
+
contract = grammar.parser_contract
|
|
529
|
+
grammar_values = contract&.configuration_values || {}
|
|
530
|
+
locations = contract&.configuration_locations || {}
|
|
531
|
+
overrides = {} #: Hash[String, Configuration::config_value]
|
|
532
|
+
algorithm = "parser.algorithm"
|
|
533
|
+
if grammar_values.key?(algorithm) && cli.key?(algorithm) &&
|
|
534
|
+
grammar_values.fetch(algorithm) != cli.fetch(algorithm)
|
|
535
|
+
overrides[algorithm] = cli.delete(algorithm)
|
|
536
|
+
end
|
|
537
|
+
source_locations = {} #: Hash[Symbol, Hash[String, Location]]
|
|
538
|
+
source_locations[:grammar] = locations unless locations.empty?
|
|
539
|
+
configuration = Configuration::Resolver.new(
|
|
540
|
+
grammar: grammar_values, cli: cli, analysis_overrides: overrides, locations: source_locations
|
|
541
|
+
)
|
|
542
|
+
@analysis_configuration = configuration
|
|
543
|
+
active = noncanonical_analysis_grammar(grammar, configuration)
|
|
544
|
+
@generation_grammar = active
|
|
545
|
+
report_noncanonical_analysis(configuration)
|
|
546
|
+
active
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
# @rbs (IR::Grammar grammar, Hash[Symbol, untyped] options, Array[Symbol] explicit_keys) ->
|
|
550
|
+
# [IR::Grammar, Symbol, IR::Automaton]
|
|
551
|
+
def construct_analysis_automaton(grammar, options, explicit_keys)
|
|
552
|
+
active = activate_analysis_grammar(grammar, options: options, explicit_keys: explicit_keys)
|
|
553
|
+
algorithm = configuration_value("parser.algorithm") #: Symbol
|
|
554
|
+
automaton = LALR::Builder.new(
|
|
555
|
+
active, algorithm: algorithm, ielr_strategy: options.fetch(:ielr_strategy, :partition),
|
|
556
|
+
remove_unreachable: options.fetch(:remove_unreachable, false),
|
|
557
|
+
entry_isolation: configuration_value("parser.entries") == :isolated
|
|
558
|
+
).build
|
|
559
|
+
[active, algorithm, automaton]
|
|
560
|
+
end
|
|
561
|
+
|
|
163
562
|
# @rbs (OptionParser parser) -> Integer?
|
|
164
563
|
def informational_result(parser)
|
|
165
564
|
return print_version if @options[:version] || @options[:runtime_version]
|
|
@@ -177,34 +576,230 @@ module Ibex
|
|
|
177
576
|
path
|
|
178
577
|
end
|
|
179
578
|
|
|
579
|
+
# @rbs () -> void
|
|
580
|
+
def validate_generation_options
|
|
581
|
+
validate_automaton_construction_options
|
|
582
|
+
|
|
583
|
+
validate_watch_generation_options if @options[:watch]
|
|
584
|
+
validate_manifest_generation_options
|
|
585
|
+
validate_action_source_generation_options
|
|
586
|
+
validate_verification_generation_options
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
# @rbs () -> void
|
|
590
|
+
def validate_automaton_construction_options
|
|
591
|
+
return unless @options[:from] == "automaton-ir"
|
|
592
|
+
|
|
593
|
+
if @configuration_explicit_options[:algorithm]
|
|
594
|
+
raise Ibex::Error, "(cli):1:1: --algorithm cannot be combined with --from=automaton-ir"
|
|
595
|
+
end
|
|
596
|
+
return unless @configuration_explicit_options[:entry_isolation]
|
|
597
|
+
|
|
598
|
+
raise Ibex::Error, "(cli):1:1: --entry-isolation cannot be combined with --from=automaton-ir"
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
# @rbs () -> void
|
|
602
|
+
def validate_manifest_generation_options
|
|
603
|
+
return unless @options[:manifest]
|
|
604
|
+
|
|
605
|
+
raise Ibex::Error, "(cli):1:1: --manifest requires --emit=ruby" unless @options[:emit] == "ruby"
|
|
606
|
+
raise Ibex::Error, "(cli):1:1: --manifest and --check-only cannot be combined" if @options[:check_only]
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
# @rbs () -> void
|
|
610
|
+
def validate_action_source_generation_options
|
|
611
|
+
return unless @options[:action_source]
|
|
612
|
+
|
|
613
|
+
raise Ibex::Error, "(cli):1:1: --action-source requires --emit=ruby" unless @options[:emit] == "ruby"
|
|
614
|
+
raise Ibex::Error, "(cli):1:1: --action-source and --check-only cannot be combined" if @options[:check_only]
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
# @rbs () -> void
|
|
618
|
+
def validate_verification_generation_options
|
|
619
|
+
return unless @options[:verify_output]
|
|
620
|
+
|
|
621
|
+
raise Ibex::Error, "(cli):1:1: --check requires --emit=ruby" unless @options[:emit] == "ruby"
|
|
622
|
+
raise Ibex::Error, "(cli):1:1: --check and --check-only cannot be combined" if @options[:check_only]
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
# @rbs () -> void
|
|
626
|
+
def validate_watch_information_options
|
|
627
|
+
return unless @options[:watch]
|
|
628
|
+
return unless %i[version runtime_version copyright help].any? { |key| @options[key] }
|
|
629
|
+
|
|
630
|
+
raise Ibex::Error, "(cli):1:1: --watch cannot be combined with information options"
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
# @rbs () -> void
|
|
634
|
+
def validate_watch_generation_options
|
|
635
|
+
raise Ibex::Error, "(cli):1:1: --watch cannot be combined with --from" if @options[:from]
|
|
636
|
+
raise Ibex::Error, "(cli):1:1: --watch cannot be combined with --check" if @options[:verify_output]
|
|
637
|
+
raise Ibex::Error, "(cli):1:1: --watch cannot be combined with --check-only" if @options[:check_only]
|
|
638
|
+
return if @options[:emit] == "ruby"
|
|
639
|
+
|
|
640
|
+
raise Ibex::Error, "(cli):1:1: --watch requires --emit=ruby with file outputs"
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
# @rbs (String input_path, ?source_paths: Array[String]) -> void
|
|
644
|
+
def validate_generation_paths!(input_path, source_paths: [input_path])
|
|
645
|
+
outputs = generation_paths(input_path).except(:input, :messages)
|
|
646
|
+
paths = outputs.filter_map do |kind, path|
|
|
647
|
+
[kind, path] if path
|
|
648
|
+
end #: Array[[Symbol, String]]
|
|
649
|
+
source_entries = source_paths.map.with_index do |path, index|
|
|
650
|
+
[index.zero? ? :input : :"include_#{index}", path]
|
|
651
|
+
end
|
|
652
|
+
source_entries << [:messages, @options[:messages]] if @options[:messages]
|
|
653
|
+
paths.concat(source_entries)
|
|
654
|
+
collision = paths.combination(2).find do |pair|
|
|
655
|
+
left = pair.fetch(0)
|
|
656
|
+
right = pair.fetch(1)
|
|
657
|
+
same_file_target?(left.fetch(1), right.fetch(1))
|
|
658
|
+
end
|
|
659
|
+
return unless collision
|
|
660
|
+
|
|
661
|
+
labels = collision.map { |kind, path| "#{kind}=#{path}" }
|
|
662
|
+
raise Ibex::Error, "(cli):1:1: paths must be distinct: #{labels.join(', ')}"
|
|
663
|
+
end
|
|
664
|
+
|
|
665
|
+
# @rbs (String left, String right) -> bool
|
|
666
|
+
def same_file_target?(left, right)
|
|
667
|
+
expanded_left = File.expand_path(left)
|
|
668
|
+
expanded_right = File.expand_path(right)
|
|
669
|
+
return true if expanded_left == expanded_right
|
|
670
|
+
|
|
671
|
+
return true if File.exist?(expanded_left) && File.exist?(expanded_right) &&
|
|
672
|
+
File.identical?(expanded_left, expanded_right)
|
|
673
|
+
|
|
674
|
+
portable_target_key(expanded_left) == portable_target_key(expanded_right)
|
|
675
|
+
rescue SystemCallError
|
|
676
|
+
expanded_left == expanded_right
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
# @rbs (String path) -> [String, String]
|
|
680
|
+
def portable_target_key(path)
|
|
681
|
+
canonical = canonical_target_path(path)
|
|
682
|
+
basename = File.basename(canonical)
|
|
683
|
+
folded = if basename.encoding == Encoding::UTF_8 && basename.valid_encoding?
|
|
684
|
+
basename.unicode_normalize(:nfc).downcase(:fold).unicode_normalize(:nfc)
|
|
685
|
+
else
|
|
686
|
+
basename.downcase
|
|
687
|
+
end
|
|
688
|
+
[File.dirname(canonical), folded]
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
# @rbs (String path, ?Hash[String, bool] seen) -> String
|
|
692
|
+
def canonical_target_path(path, seen = {})
|
|
693
|
+
suffix = [] #: Array[String]
|
|
694
|
+
cursor = File.expand_path(path)
|
|
695
|
+
until File.exist?(cursor) || File.symlink?(cursor)
|
|
696
|
+
parent = File.dirname(cursor)
|
|
697
|
+
return path if parent == cursor
|
|
698
|
+
|
|
699
|
+
suffix.unshift(File.basename(cursor))
|
|
700
|
+
cursor = parent
|
|
701
|
+
end
|
|
702
|
+
if File.symlink?(cursor)
|
|
703
|
+
raise Errno::ELOOP, cursor if seen[cursor]
|
|
704
|
+
|
|
705
|
+
seen[cursor] = true
|
|
706
|
+
target = File.expand_path(File.readlink(cursor), File.dirname(cursor))
|
|
707
|
+
return File.join(canonical_target_path(target, seen), *suffix)
|
|
708
|
+
end
|
|
709
|
+
|
|
710
|
+
File.join(File.realpath(cursor), *suffix)
|
|
711
|
+
end
|
|
712
|
+
|
|
713
|
+
# @rbs (String input_path) -> Hash[Symbol, String?]
|
|
714
|
+
def generation_paths(input_path)
|
|
715
|
+
paths = { input: input_path, messages: @options[:messages] } #: Hash[Symbol, String?]
|
|
716
|
+
if @options[:emit] == "ruby" && !@options[:check_only]
|
|
717
|
+
output = @options[:output] || default_output_path(input_path, ".rb")
|
|
718
|
+
paths[:parser] = output
|
|
719
|
+
paths[:rbs] = rbs_output_path(output) if @options[:rbs]
|
|
720
|
+
paths[:action_source] = action_source_output_path(output) if @options[:action_source]
|
|
721
|
+
paths[:manifest] = manifest_output_path_for(output) if @options[:manifest]
|
|
722
|
+
end
|
|
723
|
+
unless @options[:verify_output]
|
|
724
|
+
paths.merge!(dot: @options[:dot], mermaid: @options[:mermaid], html: @options[:html],
|
|
725
|
+
railroad: @options[:railroad])
|
|
726
|
+
paths[:report] = @options[:log_file] || default_output_path(input_path, ".output") if @options[:verbose]
|
|
727
|
+
end
|
|
728
|
+
paths
|
|
729
|
+
end
|
|
730
|
+
|
|
180
731
|
# @rbs (String path) -> Integer
|
|
181
732
|
def process_grammar(path)
|
|
182
733
|
return process_ir(path) if @options[:from]
|
|
183
734
|
|
|
735
|
+
begin_artifact_generation
|
|
184
736
|
report_status("reading #{path}")
|
|
185
|
-
|
|
186
|
-
|
|
737
|
+
resolution = resolve_grammar_path(path)
|
|
738
|
+
@generation_inputs = @last_resolver.source_records
|
|
739
|
+
@generation_sources = @generation_inputs.map(&:path)
|
|
740
|
+
validate_generation_paths!(path, source_paths: resolution.files)
|
|
741
|
+
return emit_ast(resolution.root) if @options[:emit] == "ast"
|
|
187
742
|
|
|
188
|
-
grammar = Normalizer.new(
|
|
743
|
+
grammar = Normalizer.new(resolution, mode: configuration_value("grammar.mode")).normalize
|
|
189
744
|
dispatch_grammar(grammar, path)
|
|
190
745
|
end
|
|
191
746
|
|
|
747
|
+
# @rbs (String path) -> Frontend::Resolution
|
|
748
|
+
def resolve_grammar_path(path)
|
|
749
|
+
loader = Frontend::SourceLoader.new(record_reads: true)
|
|
750
|
+
@last_resolver = Frontend::Resolver.new(path, mode: configuration_value("grammar.mode"), loader: loader)
|
|
751
|
+
@last_resolver.resolve
|
|
752
|
+
end
|
|
753
|
+
|
|
754
|
+
# @rbs (String path) -> IR::Grammar
|
|
755
|
+
def normalize_grammar_path(path)
|
|
756
|
+
source = File.binread(path)
|
|
757
|
+
if bison_source?(source)
|
|
758
|
+
require_relative "bison_import"
|
|
759
|
+
imported = BisonImport::Importer.new(source, file: path).run
|
|
760
|
+
ast = Frontend::Parser.new(imported.source, file: path, mode: :extended).parse
|
|
761
|
+
return Normalizer.new(ast, mode: :extended).normalize
|
|
762
|
+
end
|
|
763
|
+
|
|
764
|
+
Normalizer.new(resolve_grammar_path(path), mode: configuration_value("grammar.mode")).normalize
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
# @rbs (String source) -> bool
|
|
768
|
+
def bison_source?(source)
|
|
769
|
+
source.lines.count { |line| line.match?(%r{^\s*%%(?:\s|/|$)}) } >= 2
|
|
770
|
+
end
|
|
771
|
+
|
|
192
772
|
# @rbs (String path) -> Integer
|
|
193
773
|
def process_ir(path)
|
|
774
|
+
require_relative "ir/validator"
|
|
775
|
+
|
|
776
|
+
begin_artifact_generation
|
|
194
777
|
report_status("reading #{path}")
|
|
195
|
-
|
|
778
|
+
source = File.binread(path)
|
|
779
|
+
input = record_generation_input(path, source)
|
|
780
|
+
validate_generation_paths!(path, source_paths: [input.path])
|
|
781
|
+
value = IR::Validator.validate(source)
|
|
196
782
|
expected = @options[:from] == "grammar-ir" ? IR::Grammar : IR::Automaton
|
|
197
783
|
raise Ibex::Error, "#{path}:1:1: expected #{@options[:from]} input" unless value.is_a?(expected)
|
|
198
784
|
|
|
199
785
|
return dispatch_grammar(value, path) if value.is_a?(IR::Grammar)
|
|
786
|
+
return dispatch_automaton(value, path) if value.is_a?(IR::Automaton)
|
|
200
787
|
|
|
201
|
-
|
|
788
|
+
raise Ibex::Error, "#{path}:1:1: expected #{@options[:from]} input"
|
|
202
789
|
end
|
|
203
790
|
|
|
204
791
|
# @rbs (IR::Grammar grammar, String path) -> Integer
|
|
205
792
|
def dispatch_grammar(grammar, path)
|
|
793
|
+
activate_generation_grammar(grammar)
|
|
206
794
|
handle_grammar_warnings(grammar, path)
|
|
207
|
-
|
|
795
|
+
if @options[:check_only]
|
|
796
|
+
build_automaton(grammar, path) if @options[:warnings]&.include?(:error)
|
|
797
|
+
return 0
|
|
798
|
+
end
|
|
799
|
+
|
|
800
|
+
write_railroad(grammar) unless @options[:verify_output]
|
|
801
|
+
return emit_sets(grammar) if @options[:emit] == "sets"
|
|
802
|
+
return emit_lexer(grammar) if @options[:emit] == "lexer-ir"
|
|
208
803
|
return emit_grammar(grammar) if @options[:emit] == "grammar-ir"
|
|
209
804
|
return emit_automaton(grammar, path) if @options[:emit] == "automaton-ir"
|
|
210
805
|
return emit_ruby(grammar, path) if @options[:emit] == "ruby"
|
|
@@ -214,8 +809,13 @@ module Ibex
|
|
|
214
809
|
|
|
215
810
|
# @rbs (IR::Automaton automaton, String path) -> Integer
|
|
216
811
|
def dispatch_automaton(automaton, path)
|
|
812
|
+
activate_generation_grammar(automaton.grammar)
|
|
217
813
|
handle_grammar_warnings(automaton.grammar, path)
|
|
218
814
|
return 0 if @options[:check_only]
|
|
815
|
+
|
|
816
|
+
write_railroad(automaton.grammar) unless @options[:verify_output]
|
|
817
|
+
return emit_sets(automaton.grammar) if @options[:emit] == "sets"
|
|
818
|
+
return emit_lexer(automaton.grammar) if @options[:emit] == "lexer-ir"
|
|
219
819
|
return emit_grammar(automaton.grammar) if @options[:emit] == "grammar-ir"
|
|
220
820
|
return emit_loaded_automaton(automaton, path) if @options[:emit] == "automaton-ir"
|
|
221
821
|
|
|
@@ -227,6 +827,36 @@ module Ibex
|
|
|
227
827
|
raise Ibex::Error, "(cli):1:1: AST cannot be reconstructed from Automaton IR"
|
|
228
828
|
end
|
|
229
829
|
|
|
830
|
+
# @rbs (IR::Grammar grammar) -> void
|
|
831
|
+
def activate_generation_grammar(grammar)
|
|
832
|
+
@analysis_configuration = nil
|
|
833
|
+
@generation_grammar = grammar
|
|
834
|
+
effective_configuration
|
|
835
|
+
end
|
|
836
|
+
|
|
837
|
+
# @rbs (IR::Grammar grammar, Configuration::Resolver configuration) -> IR::Grammar
|
|
838
|
+
def noncanonical_analysis_grammar(grammar, configuration)
|
|
839
|
+
selection = configuration.fetch("parser.algorithm")
|
|
840
|
+
return grammar if selection.canonical
|
|
841
|
+
|
|
842
|
+
require_relative "configuration/analysis_grammar"
|
|
843
|
+
algorithm = selection.value #: Symbol
|
|
844
|
+
Configuration::AnalysisGrammar.for_algorithm(grammar, algorithm)
|
|
845
|
+
end
|
|
846
|
+
|
|
847
|
+
# @rbs (Configuration::Resolver configuration) -> void
|
|
848
|
+
def report_noncanonical_analysis(configuration)
|
|
849
|
+
selection = configuration.fetch("parser.algorithm")
|
|
850
|
+
return if selection.canonical
|
|
851
|
+
|
|
852
|
+
analysis = selection.to_h.fetch("analysis") #: Hash[String, Configuration::json_value]
|
|
853
|
+
@stderr.puts(
|
|
854
|
+
"noncanonical analysis configuration: parser.algorithm " \
|
|
855
|
+
"declared=#{analysis.fetch('declared')} selected=#{analysis.fetch('selected')} " \
|
|
856
|
+
"override=true canonical_generation=false"
|
|
857
|
+
)
|
|
858
|
+
end
|
|
859
|
+
|
|
230
860
|
# @rbs () -> Integer
|
|
231
861
|
def print_version
|
|
232
862
|
@stdout.puts("ibex #{VERSION}")
|
|
@@ -253,13 +883,40 @@ module Ibex
|
|
|
253
883
|
|
|
254
884
|
# @rbs (IR::Grammar grammar) -> Integer
|
|
255
885
|
def emit_grammar(grammar)
|
|
886
|
+
finish_artifact_generation(@generation_sources)
|
|
256
887
|
@stdout.write(IR::Serialize.dump(grammar))
|
|
257
888
|
0
|
|
258
889
|
end
|
|
259
890
|
|
|
891
|
+
# @rbs (IR::Grammar grammar) -> Integer
|
|
892
|
+
def emit_lexer(grammar)
|
|
893
|
+
lexer = grammar.lexer
|
|
894
|
+
raise Ibex::Error, "(cli):1:1: grammar does not declare a lexer" unless lexer
|
|
895
|
+
|
|
896
|
+
finish_artifact_generation(@generation_sources)
|
|
897
|
+
@stdout.write(IR::Serialize.dump(lexer))
|
|
898
|
+
0
|
|
899
|
+
end
|
|
900
|
+
|
|
901
|
+
# @rbs (IR::Grammar grammar) -> Integer
|
|
902
|
+
def emit_sets(grammar)
|
|
903
|
+
sets = Analysis::Sets.new(grammar)
|
|
904
|
+
nonterminals = grammar.nonterminals.sort_by(&:name)
|
|
905
|
+
output = {
|
|
906
|
+
nullable: nonterminals.filter_map { |symbol| symbol.name if sets.nullable?(symbol) },
|
|
907
|
+
first: nonterminals.to_h { |symbol| [symbol.name, sets.first(symbol).sort] },
|
|
908
|
+
follow: nonterminals.to_h { |symbol| [symbol.name, sets.follow(symbol).sort] }
|
|
909
|
+
}
|
|
910
|
+
finish_artifact_generation(@generation_sources)
|
|
911
|
+
@stdout.puts(JSON.pretty_generate(output))
|
|
912
|
+
0
|
|
913
|
+
end
|
|
914
|
+
|
|
260
915
|
# @rbs (IR::Grammar grammar, String input_path) -> Integer
|
|
261
916
|
def emit_automaton(grammar, input_path)
|
|
262
|
-
|
|
917
|
+
automaton = build_automaton(grammar, input_path)
|
|
918
|
+
finish_artifact_generation(@generation_sources)
|
|
919
|
+
@stdout.write(IR::Serialize.dump(automaton))
|
|
263
920
|
0
|
|
264
921
|
end
|
|
265
922
|
|
|
@@ -271,63 +928,176 @@ module Ibex
|
|
|
271
928
|
|
|
272
929
|
# @rbs (IR::Automaton automaton, String input_path) -> Integer
|
|
273
930
|
def generate_ruby(automaton, input_path)
|
|
931
|
+
@generation_automaton = automaton
|
|
932
|
+
line_mapping = configuration_value("source.line_mapping") #: Symbol
|
|
933
|
+
executable = configuration_value("build.executable") #: String?
|
|
934
|
+
table = configuration_value("table.representation") #: Symbol | String
|
|
935
|
+
embedded = configuration_value("runtime.embedded") #: bool
|
|
936
|
+
debug = configuration_value("build.debug") #: bool
|
|
937
|
+
omit_action_call = configuration_value("actions.omit_calls") #: bool?
|
|
938
|
+
superclass = configuration_value("parser.superclass") #: String?
|
|
939
|
+
cst_trivia = configuration_value("cst.trivia") #: Symbol | String
|
|
274
940
|
source = Codegen::Ruby.new(
|
|
275
|
-
automaton, table:
|
|
276
|
-
line_convert:
|
|
277
|
-
line_convert_all:
|
|
278
|
-
omit_action_call:
|
|
279
|
-
executable:
|
|
941
|
+
automaton, table: table, embedded: embedded,
|
|
942
|
+
line_convert: line_mapping != :none, debug: debug,
|
|
943
|
+
line_convert_all: line_mapping == :all,
|
|
944
|
+
omit_action_call: omit_action_call, superclass: superclass,
|
|
945
|
+
executable: executable, cst_trivia: cst_trivia,
|
|
946
|
+
error_messages: configured_error_messages(automaton)
|
|
280
947
|
).generate
|
|
281
948
|
output_path = @options[:output] || default_output_path(input_path, ".rb")
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
949
|
+
action_source = action_source_source(automaton) if @options[:action_source]
|
|
950
|
+
write_action_source(output_path, action_source) if action_source
|
|
951
|
+
register_artifact(:parser, output_path, source, mode: (0o755 if executable), status: true)
|
|
285
952
|
write_rbs(automaton, output_path) if @options[:rbs]
|
|
953
|
+
finish_artifact_generation(@generation_sources)
|
|
954
|
+
end
|
|
955
|
+
|
|
956
|
+
# @rbs (IR::Automaton automaton, String output_path, String source, String? action_source) -> Integer
|
|
957
|
+
def verify_generated_outputs(automaton, output_path, source, action_source)
|
|
958
|
+
verify_file(output_path, source, "parser")
|
|
959
|
+
verify_file(rbs_output_path(output_path), rbs_source(automaton), "RBS signature") if @options[:rbs]
|
|
960
|
+
verify_file(action_source_output_path(output_path), action_source, "action source") if action_source
|
|
961
|
+
report_status("verified #{output_path}")
|
|
286
962
|
0
|
|
287
963
|
end
|
|
288
964
|
|
|
965
|
+
# @rbs (String path, String source, String label) -> void
|
|
966
|
+
def verify_file(path, source, label)
|
|
967
|
+
raise Ibex::Error, "#{path}:1:1: generated #{label} is missing" unless File.exist?(path)
|
|
968
|
+
return if File.binread(path) == source
|
|
969
|
+
|
|
970
|
+
raise Ibex::Error, "#{path}:1:1: generated #{label} is stale; regenerate it with the same options"
|
|
971
|
+
end
|
|
972
|
+
|
|
289
973
|
# @rbs (IR::Automaton automaton, String output_path) -> void
|
|
290
974
|
def write_rbs(automaton, output_path)
|
|
975
|
+
path = rbs_output_path(output_path)
|
|
976
|
+
source = rbs_source(automaton)
|
|
977
|
+
register_artifact(:rbs, path, source, status: true)
|
|
978
|
+
end
|
|
979
|
+
|
|
980
|
+
# @rbs (String output_path) -> String
|
|
981
|
+
def rbs_output_path(output_path)
|
|
291
982
|
configured_path = @options[:rbs]
|
|
292
983
|
path = configured_path == true ? default_output_path(output_path, ".rbs") : configured_path
|
|
293
984
|
raise ArgumentError, "RBS output path is required" unless path.is_a?(String)
|
|
294
985
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
986
|
+
path
|
|
987
|
+
end
|
|
988
|
+
|
|
989
|
+
# @rbs (IR::Automaton automaton) -> String
|
|
990
|
+
def rbs_source(automaton)
|
|
991
|
+
require_relative "codegen/rbs"
|
|
992
|
+
superclass = configuration_value("parser.superclass") #: String?
|
|
993
|
+
omit_action_call = configuration_value("actions.omit_calls") #: bool?
|
|
994
|
+
Codegen::RBS.new(
|
|
995
|
+
automaton, superclass: superclass, omit_action_call: omit_action_call
|
|
996
|
+
).generate
|
|
997
|
+
end
|
|
998
|
+
|
|
999
|
+
# @rbs (String output_path, String source) -> void
|
|
1000
|
+
def write_action_source(output_path, source)
|
|
1001
|
+
path = action_source_output_path(output_path)
|
|
1002
|
+
register_artifact(:action_source, path, source, status: true)
|
|
1003
|
+
end
|
|
1004
|
+
|
|
1005
|
+
# @rbs (String output_path) -> String
|
|
1006
|
+
def action_source_output_path(output_path)
|
|
1007
|
+
configured_path = @options[:action_source]
|
|
1008
|
+
path = configured_path == true ? default_output_path(output_path, ".actions.rb") : configured_path
|
|
1009
|
+
raise Ibex::Error, "(cli):1:1: action source output path is required" unless path.is_a?(String) && !path.empty?
|
|
1010
|
+
|
|
1011
|
+
path
|
|
1012
|
+
end
|
|
1013
|
+
|
|
1014
|
+
# @rbs (IR::Automaton automaton) -> String
|
|
1015
|
+
def action_source_source(automaton)
|
|
1016
|
+
require_relative "codegen/action_source"
|
|
1017
|
+
Codegen::ActionSource.new(
|
|
1018
|
+
automaton, omit_action_call: configuration_value("actions.omit_calls")
|
|
1019
|
+
).generate
|
|
298
1020
|
end
|
|
299
1021
|
|
|
300
1022
|
# @rbs (IR::Automaton automaton, String input_path) -> Integer
|
|
301
1023
|
def emit_loaded_automaton(automaton, input_path)
|
|
302
1024
|
prepare_loaded_automaton(automaton, input_path)
|
|
1025
|
+
finish_artifact_generation(@generation_sources)
|
|
303
1026
|
@stdout.write(IR::Serialize.dump(automaton))
|
|
304
1027
|
0
|
|
305
1028
|
end
|
|
306
1029
|
|
|
307
1030
|
# @rbs (IR::Grammar grammar, String input_path) -> IR::Automaton
|
|
308
1031
|
def build_automaton(grammar, input_path)
|
|
309
|
-
|
|
310
|
-
|
|
1032
|
+
algorithm = configuration_value("parser.algorithm")
|
|
1033
|
+
report_status("building #{algorithm} automaton")
|
|
1034
|
+
automaton = LALR::Builder.new(
|
|
1035
|
+
grammar, algorithm: algorithm, ielr_strategy: @options.fetch(:ielr_strategy, :partition),
|
|
1036
|
+
remove_unreachable: @options.fetch(:remove_unreachable, false),
|
|
1037
|
+
entry_isolation: configuration_value("parser.entries") == :isolated
|
|
1038
|
+
).build
|
|
1039
|
+
write_ielr_report(grammar, automaton) if @options[:ielr_report]
|
|
311
1040
|
report_conflicts(automaton, input_path)
|
|
312
|
-
|
|
313
|
-
|
|
1041
|
+
suggest_ielr(automaton, input_path)
|
|
1042
|
+
write_report(automaton, input_path) if @options[:verbose] && !@options[:verify_output]
|
|
1043
|
+
write_visualizations(automaton) unless @options[:verify_output]
|
|
314
1044
|
automaton
|
|
315
1045
|
end
|
|
316
1046
|
|
|
1047
|
+
# @rbs (IR::Grammar grammar, IR::Automaton automaton) -> void
|
|
1048
|
+
def write_ielr_report(grammar, automaton)
|
|
1049
|
+
canonical = LALR::Builder.new(grammar, algorithm: :lr1).build
|
|
1050
|
+
@stdout.write(LALR::InadequacyReport.new(canonical, automaton).to_json)
|
|
1051
|
+
end
|
|
1052
|
+
|
|
317
1053
|
# @rbs (IR::Automaton automaton, String input_path) -> void
|
|
318
1054
|
def prepare_loaded_automaton(automaton, input_path)
|
|
319
1055
|
report_conflicts(automaton, input_path)
|
|
320
|
-
|
|
321
|
-
|
|
1056
|
+
suggest_ielr(automaton, input_path)
|
|
1057
|
+
write_report(automaton, input_path) if @options[:verbose] && !@options[:verify_output]
|
|
1058
|
+
write_visualizations(automaton) unless @options[:verify_output]
|
|
322
1059
|
end
|
|
323
1060
|
|
|
324
1061
|
# @rbs (IR::Automaton automaton) -> void
|
|
325
1062
|
def write_visualizations(automaton)
|
|
326
1063
|
dot_path = @options[:dot]
|
|
1064
|
+
mermaid_path = @options[:mermaid]
|
|
327
1065
|
html_path = @options[:html]
|
|
328
|
-
|
|
329
|
-
|
|
1066
|
+
if dot_path
|
|
1067
|
+
require_relative "codegen/dot"
|
|
1068
|
+
register_artifact(:dot, dot_path, Codegen::Dot.render(automaton))
|
|
1069
|
+
end
|
|
1070
|
+
if mermaid_path
|
|
1071
|
+
require_relative "codegen/mermaid"
|
|
1072
|
+
register_artifact(:mermaid, mermaid_path, Codegen::Mermaid.render(automaton))
|
|
1073
|
+
end
|
|
1074
|
+
return unless html_path
|
|
1075
|
+
|
|
1076
|
+
require_relative "codegen/html"
|
|
1077
|
+
register_artifact(:html, html_path, Codegen::HTML.render(automaton))
|
|
1078
|
+
end
|
|
1079
|
+
|
|
1080
|
+
# @rbs (IR::Grammar grammar) -> void
|
|
1081
|
+
def write_railroad(grammar)
|
|
1082
|
+
path = @options[:railroad]
|
|
1083
|
+
return unless path
|
|
1084
|
+
|
|
1085
|
+
require_relative "codegen/railroad"
|
|
1086
|
+
register_artifact(:railroad, path, Codegen::Railroad.render(grammar))
|
|
1087
|
+
end
|
|
1088
|
+
|
|
1089
|
+
# @rbs (String output_path) -> String
|
|
1090
|
+
def manifest_output_path_for(output_path)
|
|
1091
|
+
configured = @options[:manifest]
|
|
1092
|
+
return configured if configured.is_a?(String) && !configured.empty?
|
|
1093
|
+
|
|
1094
|
+
default_output_path(output_path, ".ibex.json")
|
|
330
1095
|
end
|
|
331
1096
|
end
|
|
1097
|
+
CONFIG_SUBCOMMAND_HELP = [
|
|
1098
|
+
" coverage collect, merge, or check runtime coverage",
|
|
1099
|
+
" config explain effective configuration without running user code"
|
|
1100
|
+
].join("\n").freeze #: String
|
|
1101
|
+
autoload :CLIConfig, File.join(CLI_FEATURE_ROOT, "config")
|
|
332
1102
|
# rubocop:enable Metrics/ClassLength
|
|
333
1103
|
end
|