ibex 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +95 -272
- data/docs/architecture.md +187 -35
- data/docs/bison-import.md +103 -0
- data/docs/comparison-policy.md +127 -0
- data/docs/configuration-model.md +59 -0
- data/docs/configuration-report.md +28 -0
- data/docs/conflict-explanation-reviews/v1/records/README.md +28 -0
- data/docs/conflict-explanation-study.md +62 -0
- data/docs/construction-profiling.md +157 -0
- data/docs/cst-migration.md +3 -4
- data/docs/cst.md +24 -0
- data/docs/decisions/0000-template.md +24 -0
- data/docs/decisions/0001-separate-ir-pipeline.md +34 -0
- data/docs/decisions/0002-opaque-user-code-boundary.md +32 -0
- data/docs/decisions/0003-self-hosted-grammar-frontend.md +32 -0
- data/docs/decisions/0004-shared-semantic-and-lossless-source-model.md +33 -0
- data/docs/decisions/0005-contained-grammar-composition.md +34 -0
- data/docs/decisions/0006-bounded-structural-grammar-lowering.md +32 -0
- data/docs/decisions/0007-shared-parser-construction-pipeline.md +33 -0
- data/docs/decisions/0008-versioned-runtime-package-boundary.md +36 -0
- data/docs/decisions/0009-isolated-parser-sessions.md +34 -0
- data/docs/decisions/0010-committed-runtime-observation.md +34 -0
- data/docs/decisions/0011-versioned-semantic-action-boundary.md +37 -0
- data/docs/decisions/0012-bounded-nonexecuting-analysis.md +37 -0
- data/docs/decisions/0013-transactional-generation-publication.md +37 -0
- data/docs/decisions/0014-versioned-generated-lexer.md +35 -0
- data/docs/decisions/0015-worker-isolated-browser-analysis.md +32 -0
- data/docs/decisions/0016-red-green-concrete-syntax.md +34 -0
- data/docs/decisions/0017-persistent-syntax-artifacts.md +35 -0
- data/docs/decisions/0018-conservative-incremental-syntax-reuse.md +38 -0
- data/docs/decisions/0019-runtime-syntax-session-boundary.md +51 -0
- data/docs/decisions/0020-grammar-ir-parser-contract.md +65 -0
- data/docs/decisions/0021-data-only-parser-table-sidecar.md +50 -0
- data/docs/decisions/0022-manifest-bound-verification-report.md +77 -0
- data/docs/decisions/0023-syntax-only-repair-results.md +48 -0
- data/docs/decisions/0024-direct-ielr-construction.md +42 -0
- data/docs/decisions/README.md +74 -0
- data/docs/declarative-configuration.md +262 -0
- data/docs/development.md +179 -2
- data/docs/direct-ielr-decision.md +120 -0
- data/docs/direct-multi-entry-decision.md +82 -0
- data/docs/editor-setup.md +2 -1
- data/docs/error-ux-review-rubric-v1.md +117 -0
- data/docs/error-ux-reviews/v1/records/README.md +22 -0
- data/docs/error-ux-round2-review-status-v1.json +27 -0
- data/docs/error-ux-round2-reviews/v1/records/README.md +30 -0
- data/docs/error-ux-round2-v1.json +1581 -0
- data/docs/error-ux-round2.md +111 -0
- data/docs/error-ux.md +54 -0
- data/docs/getting-started.md +80 -0
- data/docs/grammar-reference.md +184 -13
- data/docs/ielr-design.md +43 -0
- data/docs/ielr.md +92 -0
- data/docs/ja/bison-import.md +51 -0
- data/docs/ja/stable-api.md +53 -0
- data/docs/lexer-construction-profile.md +109 -0
- data/docs/lexer-migration.md +5 -0
- data/docs/maturity.md +128 -0
- data/docs/project-site-strategy.md +54 -0
- data/docs/racc-migration-evidence.md +45 -0
- data/docs/racc-migration.md +11 -0
- data/docs/release-readiness.md +126 -68
- data/docs/repair-semantics.md +123 -0
- data/docs/runtime-abi-evolution.md +307 -0
- data/docs/stability.md +144 -34
- data/docs/status.md +43 -0
- data/docs/syntax-sessions.md +183 -0
- data/docs/table-artifact.md +125 -0
- data/docs/test-interactions.md +219 -0
- data/docs/verification-report.md +137 -0
- data/docs/verifier-trust-boundary.md +199 -0
- data/docs/workloads.md +132 -0
- data/lib/ibex/analysis/digraph.rb +128 -0
- data/lib/ibex/analysis.rb +1 -0
- data/lib/ibex/bison_import/importer.rb +516 -0
- data/lib/ibex/bison_import/tokenizer.rb +260 -0
- data/lib/ibex/bison_import.rb +200 -0
- data/lib/ibex/bounded_subprocess.rb +171 -0
- data/lib/ibex/cli/ambiguity.rb +14 -5
- data/lib/ibex/cli/analysis.rb +134 -0
- data/lib/ibex/cli/bison_import.rb +121 -0
- data/lib/ibex/cli/config.rb +128 -0
- data/lib/ibex/cli/diagnostics.rb +31 -11
- data/lib/ibex/cli/documentation.rb +11 -8
- data/lib/ibex/cli/equiv.rb +169 -0
- data/lib/ibex/cli/error_messages.rb +11 -4
- data/lib/ibex/cli/explain.rb +14 -5
- data/lib/ibex/cli/fix.rb +203 -0
- data/lib/ibex/cli/formatting.rb +11 -10
- data/lib/ibex/cli/fuzz.rb +200 -0
- data/lib/ibex/cli/fuzz_regressions.rb +145 -0
- data/lib/ibex/cli/generation_artifacts.rb +53 -2
- data/lib/ibex/cli/generation_error_messages.rb +1 -1
- data/lib/ibex/cli/grammar_tests.rb +32 -14
- data/lib/ibex/cli/ir_tools.rb +5 -61
- data/lib/ibex/cli/outputs.rb +60 -33
- data/lib/ibex/cli/reduce.rb +202 -0
- data/lib/ibex/cli/reduce_reporting.rb +71 -0
- data/lib/ibex/cli/samples.rb +49 -23
- data/lib/ibex/cli/verify.rb +116 -0
- data/lib/ibex/cli/watch.rb +6 -5
- data/lib/ibex/cli.rb +357 -56
- data/lib/ibex/codegen/action_locations.rb +1 -1
- data/lib/ibex/codegen/action_method_source.rb +5 -6
- data/lib/ibex/codegen/action_source.rb +3 -2
- data/lib/ibex/codegen/ambiguity.rb +5 -4
- data/lib/ibex/codegen/explain.rb +123 -55
- data/lib/ibex/codegen/generated_action_abi.rb +10 -5
- data/lib/ibex/codegen/rbs.rb +15 -7
- data/lib/ibex/codegen/report.rb +25 -13
- data/lib/ibex/codegen/ruby.rb +28 -64
- data/lib/ibex/codegen/ruby_actions.rb +9 -6
- data/lib/ibex/codegen/ruby_syntax.rb +15 -9
- data/lib/ibex/configuration/analysis_grammar.rb +35 -0
- data/lib/ibex/configuration/explanation.rb +421 -0
- data/lib/ibex/configuration/inspector.rb +232 -0
- data/lib/ibex/configuration.rb +580 -0
- data/lib/ibex/coverage/collector.rb +21 -11
- data/lib/ibex/coverage/event_stream.rb +13 -7
- data/lib/ibex/coverage/report.rb +26 -18
- data/lib/ibex/coverage/runtime_event_validator.rb +30 -21
- data/lib/ibex/delta_reducer.rb +99 -0
- data/lib/ibex/diff.rb +140 -0
- data/lib/ibex/equiv/machine.rb +135 -0
- data/lib/ibex/equiv.rb +373 -0
- data/lib/ibex/fix.rb +557 -0
- data/lib/ibex/frontend/ast.rb +22 -2
- data/lib/ibex/frontend/bootstrap_parser.rb +6 -13
- data/lib/ibex/frontend/diagnostic.rb +1 -1
- data/lib/ibex/frontend/formatter.rb +72 -26
- data/lib/ibex/frontend/generated_parser.rb +147 -117
- data/lib/ibex/frontend/generated_parser_base.rb +7 -3
- data/lib/ibex/frontend/generated_parser_includes.rb +1 -11
- data/lib/ibex/frontend/generation.rb +1 -1
- data/lib/ibex/frontend/parser/declarations.rb +17 -2
- data/lib/ibex/frontend/parser_configuration_support.rb +56 -0
- data/lib/ibex/frontend/regenerator.rb +1 -0
- data/lib/ibex/frontend/resolution.rb +2 -1
- data/lib/ibex/frontend/resolver.rb +1 -1
- data/lib/ibex/frontend/rule_documentation.rb +2 -1
- data/lib/ibex/frontend/source_cursor.rb +2 -2
- data/lib/ibex/frontend/source_span.rb +9 -1
- data/lib/ibex/frontend/token_adapter/declaration_state.rb +38 -6
- data/lib/ibex/frontend/token_adapter.rb +10 -0
- data/lib/ibex/frontend.rb +1 -0
- data/lib/ibex/fuzz.rb +219 -0
- data/lib/ibex/generation_input.rb +1 -1
- data/lib/ibex/generation_manifest.rb +36 -25
- data/lib/ibex/generation_transaction.rb +1 -1
- data/lib/ibex/generation_transaction_recovery.rb +4 -4
- data/lib/ibex/generation_transaction_validation.rb +2 -2
- data/lib/ibex/grammar_tests.rb +1 -1
- data/lib/ibex/ir/automaton_ir.rb +61 -19
- data/lib/ibex/ir/grammar_ir.rb +76 -45
- data/lib/ibex/ir/lexer_ir.rb +5 -5
- data/lib/ibex/ir/parser_contract.rb +135 -0
- data/lib/ibex/ir/serialize.rb +203 -76
- data/lib/ibex/ir/validator/automaton.rb +64 -34
- data/lib/ibex/ir/validator/base.rb +51 -33
- data/lib/ibex/ir/validator/grammar.rb +113 -83
- data/lib/ibex/ir/validator/lexer.rb +2 -2
- data/lib/ibex/ir/validator.rb +2 -1
- data/lib/ibex/ir.rb +16 -3
- data/lib/ibex/lalr/build_metrics.rb +50 -2
- data/lib/ibex/lalr/builder.rb +191 -56
- data/lib/ibex/lalr/conflict_search.rb +15 -4
- data/lib/ibex/lalr/counterexample.rb +19 -14
- data/lib/ibex/lalr/direct_lookaheads.rb +110 -57
- data/lib/ibex/lalr/goto_follows.rb +229 -0
- data/lib/ibex/lalr/ielr/annotator.rb +214 -0
- data/lib/ibex/lalr/ielr/bits.rb +28 -0
- data/lib/ibex/lalr/ielr/inadequacy.rb +47 -0
- data/lib/ibex/lalr/ielr/item_lookaheads.rb +78 -0
- data/lib/ibex/lalr/ielr/pipeline.rb +75 -0
- data/lib/ibex/lalr/ielr/split_stability.rb +78 -0
- data/lib/ibex/lalr/ielr/split_state.rb +20 -0
- data/lib/ibex/lalr/ielr/state_splitter.rb +258 -0
- data/lib/ibex/lalr/ielr_partition.rb +22 -8
- data/lib/ibex/lalr/inadequacy_report.rb +50 -0
- data/lib/ibex/lalr/lookahead_propagation.rb +111 -0
- data/lib/ibex/lalr/lr0_collection.rb +121 -0
- data/lib/ibex/lalr/unreachable_states.rb +80 -0
- data/lib/ibex/lalr.rb +52 -1
- data/lib/ibex/location.rb +3 -3
- data/lib/ibex/lsp/document_handlers.rb +9 -7
- data/lib/ibex/lsp/initialization_handlers.rb +9 -7
- data/lib/ibex/lsp/navigation_handlers.rb +25 -11
- data/lib/ibex/lsp/parser_configuration_assistance.rb +149 -0
- data/lib/ibex/lsp/position_codec.rb +6 -2
- data/lib/ibex/lsp/request_handlers.rb +3 -2
- data/lib/ibex/lsp/request_support.rb +14 -7
- data/lib/ibex/lsp/server.rb +13 -11
- data/lib/ibex/lsp/symbol_index.rb +13 -13
- data/lib/ibex/lsp/symbol_index_builder.rb +30 -20
- data/lib/ibex/lsp/symbol_occurrence.rb +8 -2
- data/lib/ibex/lsp/transport.rb +13 -3
- data/lib/ibex/lsp/workspace.rb +5 -4
- data/lib/ibex/lsp/workspace_analyzer.rb +1 -1
- data/lib/ibex/lsp.rb +1 -0
- data/lib/ibex/messages/en.yml +28 -0
- data/lib/ibex/messages/ja.yml +28 -0
- data/lib/ibex/messages.rb +68 -0
- data/lib/ibex/metrics.rb +175 -0
- data/lib/ibex/normalize/declarations.rb +2 -0
- data/lib/ibex/normalize/diagnostics.rb +63 -38
- data/lib/ibex/normalize/expander.rb +5 -4
- data/lib/ibex/normalize/expression.rb +8 -6
- data/lib/ibex/normalize/grammar_builder.rb +26 -0
- data/lib/ibex/normalize/inline_expansion.rb +100 -49
- data/lib/ibex/normalize/lexer.rb +3 -3
- data/lib/ibex/normalize/parameter_ebnf_lowering.rb +11 -10
- data/lib/ibex/normalize/parameter_lowering.rb +40 -23
- data/lib/ibex/normalize/parameters.rb +31 -4
- data/lib/ibex/normalize/parser_configuration.rb +70 -0
- data/lib/ibex/normalize.rb +10 -20
- data/lib/ibex/racc_migration/report.rb +6 -3
- data/lib/ibex/rake_task.rb +1 -1
- data/lib/ibex/samples.rb +43 -13
- data/lib/ibex/table_artifact/builder.rb +266 -0
- data/lib/ibex/table_artifact/cst_projection.rb +70 -0
- data/lib/ibex/table_artifact/document.rb +39 -0
- data/lib/ibex/table_artifact/executor.rb +187 -0
- data/lib/ibex/table_artifact/serializer.rb +57 -0
- data/lib/ibex/table_artifact/validator/metadata.rb +179 -0
- data/lib/ibex/table_artifact/validator/support.rb +86 -0
- data/lib/ibex/table_artifact/validator/tables.rb +238 -0
- data/lib/ibex/table_artifact/validator.rb +253 -0
- data/lib/ibex/table_artifact.rb +88 -0
- data/lib/ibex/table_simulation/result.rb +6 -2
- data/lib/ibex/table_simulation/step.rb +3 -1
- data/lib/ibex/tables.rb +14 -0
- data/lib/ibex/verifiable_generation_bundle.rb +86 -0
- data/lib/ibex/verification_report/builder.rb +159 -0
- data/lib/ibex/verification_report/canonical_ir.rb +123 -0
- data/lib/ibex/verification_report/logical_path.rb +68 -0
- data/lib/ibex/verification_report/validator.rb +329 -0
- data/lib/ibex/verification_report.rb +69 -0
- data/lib/ibex/verify/action_correspondence.rb +138 -0
- data/lib/ibex/verify/language_witness.rb +295 -0
- data/lib/ibex/verify/reference_collection.rb +190 -0
- data/lib/ibex/verify/result.rb +73 -0
- data/lib/ibex/verify/verifier.rb +598 -0
- data/lib/ibex/verify.rb +15 -0
- data/lib/ibex/version.rb +1 -1
- data/lib/ibex/watch/runner.rb +10 -1
- data/lib/ibex/watch/source_snapshot.rb +13 -8
- data/lib/ibex.rb +10 -0
- data/schema/{automaton-ir-v1.schema.json → automaton-ir-definitions.schema.json} +6 -6
- data/schema/{automaton-ir-v2.schema.json → automaton-ir.schema.json} +14 -7
- data/schema/bison-import-v1.schema.json +106 -0
- data/schema/conflict-explanation-review-v1.schema.json +196 -0
- data/schema/conflict-explanation-study-v1.schema.json +528 -0
- data/schema/construction-profile-v1.schema.json +779 -0
- data/schema/diff-v1.schema.json +41 -0
- data/schema/direct-ielr-decision-v1.schema.json +200 -0
- data/schema/equiv-v1.schema.json +64 -0
- data/schema/error-ux-review-v1.schema.json +609 -0
- data/schema/error-ux-round2-review-v1.schema.json +191 -0
- data/schema/error-ux-round2-v1.schema.json +519 -0
- data/schema/explain-v1.schema.json +63 -1
- data/schema/fix-v1.schema.json +64 -0
- data/schema/fix-v2.schema.json +66 -0
- data/schema/fix-v3.schema.json +101 -0
- data/schema/fuzz-regression-v1.schema.json +79 -0
- data/schema/fuzz-v1.schema.json +114 -0
- data/schema/{grammar-ir-v2.schema.json → grammar-ir-extensions.schema.json} +20 -65
- data/schema/{grammar-ir-v1.schema.json → grammar-ir-foundation.schema.json} +3 -3
- data/schema/grammar-ir.schema.json +271 -0
- data/schema/ielr-benchmark-v1.schema.json +85 -0
- data/schema/lexer-profile-v1.schema.json +491 -0
- data/schema/metrics-v1.schema.json +60 -0
- data/schema/reduce-v1.schema.json +22 -0
- data/schema/reduce-v2.schema.json +63 -0
- data/schema/table-artifact-v1.schema.json +377 -0
- data/schema/verification-report-v1.schema.json +222 -0
- data/schema/verify-v1.schema.json +42 -0
- data/sig/ibex/analysis/digraph.rbs +19 -0
- data/sig/ibex/bison_import/importer.rbs +140 -0
- data/sig/ibex/bison_import/tokenizer.rbs +91 -0
- data/sig/ibex/bison_import.rbs +95 -0
- data/sig/ibex/bounded_subprocess.rbs +76 -0
- data/sig/ibex/cli/ambiguity.rbs +6 -0
- data/sig/ibex/cli/analysis.rbs +43 -0
- data/sig/ibex/cli/bison_import.rbs +32 -0
- data/sig/ibex/cli/config.rbs +35 -0
- data/sig/ibex/cli/diagnostics.rbs +16 -3
- data/sig/ibex/cli/documentation.rbs +5 -1
- data/sig/ibex/cli/equiv.rbs +49 -0
- data/sig/ibex/cli/error_messages.rbs +6 -0
- data/sig/ibex/cli/explain.rbs +6 -0
- data/sig/ibex/cli/fix.rbs +53 -0
- data/sig/ibex/cli/formatting.rbs +5 -1
- data/sig/ibex/cli/fuzz.rbs +47 -0
- data/sig/ibex/cli/fuzz_regressions.rbs +40 -0
- data/sig/ibex/cli/generation_artifacts.rbs +21 -2
- data/sig/ibex/cli/generation_error_messages.rbs +2 -2
- data/sig/ibex/cli/grammar_tests.rbs +15 -3
- data/sig/ibex/cli/ir_tools.rbs +7 -19
- data/sig/ibex/cli/outputs.rbs +9 -3
- data/sig/ibex/cli/reduce.rbs +60 -0
- data/sig/ibex/cli/reduce_reporting.rbs +27 -0
- data/sig/ibex/cli/samples.rbs +8 -0
- data/sig/ibex/cli/verify.rbs +28 -0
- data/sig/ibex/cli/watch.rbs +2 -2
- data/sig/ibex/cli.rbs +79 -5
- data/sig/ibex/codegen/action_method_source.rbs +4 -4
- data/sig/ibex/codegen/explain.rbs +45 -25
- data/sig/ibex/codegen/generated_action_abi.rbs +14 -10
- data/sig/ibex/codegen/rbs.rbs +12 -10
- data/sig/ibex/codegen/report.rbs +12 -12
- data/sig/ibex/codegen/ruby.rbs +18 -15
- data/sig/ibex/codegen/ruby_actions.rbs +6 -6
- data/sig/ibex/codegen/ruby_syntax.rbs +10 -8
- data/sig/ibex/configuration/analysis_grammar.rbs +13 -0
- data/sig/ibex/configuration/explanation.rbs +195 -0
- data/sig/ibex/configuration/inspector.rbs +53 -0
- data/sig/ibex/configuration.rbs +242 -0
- data/sig/ibex/coverage/collector.rbs +16 -14
- data/sig/ibex/coverage/event_stream.rbs +12 -10
- data/sig/ibex/coverage/report.rbs +20 -18
- data/sig/ibex/coverage/runtime_event_validator.rbs +38 -36
- data/sig/ibex/delta_reducer.rbs +38 -0
- data/sig/ibex/diff.rbs +47 -0
- data/sig/ibex/equiv/machine.rbs +54 -0
- data/sig/ibex/equiv.rbs +129 -0
- data/sig/ibex/fix.rbs +138 -0
- data/sig/ibex/frontend/ast.rbs +33 -7
- data/sig/ibex/frontend/bootstrap_parser.rbs +2 -0
- data/sig/ibex/frontend/diagnostic.rbs +2 -2
- data/sig/ibex/frontend/formatter.rbs +38 -30
- data/sig/ibex/frontend/generated_parser.rbs +87 -77
- data/sig/ibex/frontend/generated_parser_base.rbs +4 -2
- data/sig/ibex/frontend/parser/declarations.rbs +3 -0
- data/sig/ibex/frontend/parser_configuration_support.rbs +27 -0
- data/sig/ibex/frontend/resolution.rbs +3 -2
- data/sig/ibex/frontend/source_cursor.rbs +2 -2
- data/sig/ibex/frontend/source_span.rbs +5 -2
- data/sig/ibex/frontend/token_adapter/declaration_state.rbs +13 -1
- data/sig/ibex/frontend/token_adapter.rbs +6 -0
- data/sig/ibex/fuzz.rbs +71 -0
- data/sig/ibex/generation_input.rbs +2 -2
- data/sig/ibex/generation_manifest.rbs +35 -32
- data/sig/ibex/generation_transaction_recovery.rbs +2 -2
- data/sig/ibex/generation_transaction_validation.rbs +2 -2
- data/sig/ibex/grammar_tests.rbs +2 -2
- data/sig/ibex/ir/automaton_ir.rbs +30 -11
- data/sig/ibex/ir/grammar_ir.rbs +41 -27
- data/sig/ibex/ir/lexer_ir.rbs +8 -8
- data/sig/ibex/ir/parser_contract.rbs +69 -0
- data/sig/ibex/ir/serialize.rbs +63 -28
- data/sig/ibex/ir/validator/automaton.rbs +47 -44
- data/sig/ibex/ir/validator/base.rbs +35 -31
- data/sig/ibex/ir/validator/grammar.rbs +78 -67
- data/sig/ibex/ir/validator/lexer.rbs +4 -4
- data/sig/ibex/ir.rbs +9 -3
- data/sig/ibex/lalr/build_metrics.rbs +42 -2
- data/sig/ibex/lalr/builder.rbs +75 -24
- data/sig/ibex/lalr/conflict_search.rbs +5 -2
- data/sig/ibex/lalr/counterexample.rbs +17 -14
- data/sig/ibex/lalr/direct_lookaheads.rbs +35 -28
- data/sig/ibex/lalr/goto_follows.rbs +89 -0
- data/sig/ibex/lalr/ielr/annotator.rbs +67 -0
- data/sig/ibex/lalr/ielr/bits.rbs +14 -0
- data/sig/ibex/lalr/ielr/inadequacy.rbs +24 -0
- data/sig/ibex/lalr/ielr/item_lookaheads.rbs +35 -0
- data/sig/ibex/lalr/ielr/pipeline.rbs +17 -0
- data/sig/ibex/lalr/ielr/split_stability.rbs +27 -0
- data/sig/ibex/lalr/ielr/split_state.rbs +14 -0
- data/sig/ibex/lalr/ielr/state_splitter.rbs +76 -0
- data/sig/ibex/lalr/ielr_partition.rbs +17 -5
- data/sig/ibex/lalr/inadequacy_report.rbs +21 -0
- data/sig/ibex/lalr/lookahead_propagation.rbs +38 -0
- data/sig/ibex/lalr/lr0_collection.rbs +50 -0
- data/sig/ibex/lalr/unreachable_states.rbs +25 -0
- data/sig/ibex/lalr.rbs +11 -1
- data/sig/ibex/location.rbs +6 -6
- data/sig/ibex/lsp/document_handlers.rbs +8 -8
- data/sig/ibex/lsp/initialization_handlers.rbs +12 -12
- data/sig/ibex/lsp/navigation_handlers.rbs +15 -12
- data/sig/ibex/lsp/parser_configuration_assistance.rbs +49 -0
- data/sig/ibex/lsp/position_codec.rbs +8 -4
- data/sig/ibex/lsp/request_handlers.rbs +4 -4
- data/sig/ibex/lsp/request_support.rbs +8 -8
- data/sig/ibex/lsp/server.rbs +16 -16
- data/sig/ibex/lsp/symbol_index.rbs +20 -21
- data/sig/ibex/lsp/symbol_index_builder.rbs +9 -8
- data/sig/ibex/lsp/symbol_occurrence.rbs +11 -5
- data/sig/ibex/lsp/transport.rbs +18 -6
- data/sig/ibex/lsp/workspace.rbs +3 -2
- data/sig/ibex/lsp/workspace_analyzer.rbs +1 -1
- data/sig/ibex/messages.rbs +26 -0
- data/sig/ibex/metrics.rbs +50 -0
- data/sig/ibex/normalize/diagnostics.rbs +4 -4
- data/sig/ibex/normalize/expander.rbs +2 -2
- data/sig/ibex/normalize/expression.rbs +10 -8
- data/sig/ibex/normalize/grammar_builder.rbs +11 -0
- data/sig/ibex/normalize/inline_expansion.rbs +59 -50
- data/sig/ibex/normalize/lexer.rbs +4 -4
- data/sig/ibex/normalize/parameter_ebnf_lowering.rbs +15 -14
- data/sig/ibex/normalize/parameter_lowering.rbs +18 -18
- data/sig/ibex/normalize/parameters.rbs +13 -8
- data/sig/ibex/normalize/parser_configuration.rbs +23 -0
- data/sig/ibex/normalize.rbs +11 -5
- data/sig/ibex/racc_migration/report.rbs +8 -6
- data/sig/ibex/rake_task.rbs +1 -1
- data/sig/ibex/samples.rbs +13 -4
- data/sig/ibex/table_artifact/builder.rbs +93 -0
- data/sig/ibex/table_artifact/cst_projection.rbs +20 -0
- data/sig/ibex/table_artifact/document.rbs +27 -0
- data/sig/ibex/table_artifact/executor.rbs +66 -0
- data/sig/ibex/table_artifact/serializer.rbs +25 -0
- data/sig/ibex/table_artifact/validator/metadata.rbs +52 -0
- data/sig/ibex/table_artifact/validator/support.rbs +46 -0
- data/sig/ibex/table_artifact/validator/tables.rbs +63 -0
- data/sig/ibex/table_artifact/validator.rbs +66 -0
- data/sig/ibex/table_artifact.rbs +32 -0
- data/sig/ibex/table_simulation/result.rbs +8 -4
- data/sig/ibex/table_simulation/step.rbs +4 -2
- data/sig/ibex/tables.rbs +10 -9
- data/sig/ibex/verifiable_generation_bundle.rbs +24 -0
- data/sig/ibex/verification_report/builder.rbs +53 -0
- data/sig/ibex/verification_report/canonical_ir.rbs +41 -0
- data/sig/ibex/verification_report/logical_path.rbs +34 -0
- data/sig/ibex/verification_report/validator.rbs +114 -0
- data/sig/ibex/verification_report.rbs +44 -0
- data/sig/ibex/verify/action_correspondence.rbs +50 -0
- data/sig/ibex/verify/language_witness.rbs +112 -0
- data/sig/ibex/verify/reference_collection.rbs +63 -0
- data/sig/ibex/verify/result.rbs +52 -0
- data/sig/ibex/verify/verifier.rbs +170 -0
- data/sig/ibex/verify.rbs +6 -0
- data/sig/ibex/watch/runner.rbs +12 -2
- data/sig/ibex/watch/source_snapshot.rbs +13 -9
- metadata +232 -12
- data/lib/ibex/ir/migration.rb +0 -120
- data/sig/ibex/ir/migration.rbs +0 -34
|
@@ -20,10 +20,10 @@ module Ibex
|
|
|
20
20
|
@snapshot_state = files.to_h do |file|
|
|
21
21
|
snapshot = store.snapshot_for(file)
|
|
22
22
|
[file, snapshot && [snapshot.fetch(:version), snapshot.fetch(:source)]]
|
|
23
|
-
end #: Hash[String,
|
|
23
|
+
end #: Hash[String, [Integer?, String]?]
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
# @rbs (String path,
|
|
26
|
+
# @rbs (String path, lsp_object position) -> Array[lsp_object]
|
|
27
27
|
def definition(path, position)
|
|
28
28
|
occurrence = occurrence_at(path, position)
|
|
29
29
|
return [] unless occurrence
|
|
@@ -32,8 +32,7 @@ module Ibex
|
|
|
32
32
|
matching(occurrence.key, role: :definition).map { |entry| location(entry) }
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
# @rbs (String path,
|
|
36
|
-
# Array[Hash[String, untyped]]
|
|
35
|
+
# @rbs (String path, lsp_object position, ?include_declaration: bool) -> Array[lsp_object]
|
|
37
36
|
def references(path, position, include_declaration: false)
|
|
38
37
|
occurrence = occurrence_at(path, position)
|
|
39
38
|
return [] unless occurrence
|
|
@@ -43,13 +42,13 @@ module Ibex
|
|
|
43
42
|
entries.map { |entry| location(entry) }
|
|
44
43
|
end
|
|
45
44
|
|
|
46
|
-
# @rbs (String path,
|
|
45
|
+
# @rbs (String path, lsp_object position) -> lsp_object?
|
|
47
46
|
def prepare_rename(path, position)
|
|
48
47
|
occurrence = renameable_occurrence(path, position)
|
|
49
48
|
{ "range" => range(occurrence), "placeholder" => occurrence.name }
|
|
50
49
|
end
|
|
51
50
|
|
|
52
|
-
# @rbs (String path,
|
|
51
|
+
# @rbs (String path, lsp_object position, String new_name) -> lsp_object
|
|
53
52
|
def rename(path, position, new_name)
|
|
54
53
|
ensure_fresh!
|
|
55
54
|
occurrence = renameable_occurrence(path, position)
|
|
@@ -78,7 +77,7 @@ module Ibex
|
|
|
78
77
|
{ "documentChanges" => document_changes }
|
|
79
78
|
end
|
|
80
79
|
|
|
81
|
-
# @rbs (String path,
|
|
80
|
+
# @rbs (String path, lsp_object position) -> lsp_object?
|
|
82
81
|
def hover(path, position)
|
|
83
82
|
occurrence = occurrence_at(path, position)
|
|
84
83
|
return unless occurrence
|
|
@@ -94,7 +93,7 @@ module Ibex
|
|
|
94
93
|
|
|
95
94
|
private
|
|
96
95
|
|
|
97
|
-
# @rbs (String path,
|
|
96
|
+
# @rbs (String path, lsp_object position) -> SymbolOccurrence?
|
|
98
97
|
def occurrence_at(path, position)
|
|
99
98
|
document = @documents[path]
|
|
100
99
|
return unless document
|
|
@@ -106,17 +105,17 @@ module Ibex
|
|
|
106
105
|
candidates.min_by { |entry| entry.span.length }
|
|
107
106
|
end
|
|
108
107
|
|
|
109
|
-
# @rbs (
|
|
108
|
+
# @rbs (symbol_key key, ?role: Symbol?) -> Array[SymbolOccurrence]
|
|
110
109
|
def matching(key, role: nil)
|
|
111
110
|
@occurrences.select { |entry| entry.key == key && (!role || entry.role == role) }
|
|
112
111
|
end
|
|
113
112
|
|
|
114
|
-
# @rbs (SymbolOccurrence occurrence) ->
|
|
113
|
+
# @rbs (SymbolOccurrence occurrence) -> lsp_object
|
|
115
114
|
def location(occurrence)
|
|
116
115
|
{ "uri" => @store.uri_for(occurrence.path), "range" => range(occurrence) }
|
|
117
116
|
end
|
|
118
117
|
|
|
119
|
-
# @rbs (SymbolOccurrence occurrence) ->
|
|
118
|
+
# @rbs (SymbolOccurrence occurrence) -> lsp_object
|
|
120
119
|
def include_target_location(occurrence)
|
|
121
120
|
target = occurrence.data.fetch(:target)
|
|
122
121
|
point = { "line" => 0, "character" => 0 }
|
|
@@ -129,7 +128,7 @@ module Ibex
|
|
|
129
128
|
PositionCodec.new(document.source).range(occurrence.span)
|
|
130
129
|
end
|
|
131
130
|
|
|
132
|
-
# @rbs (String path,
|
|
131
|
+
# @rbs (String path, lsp_object position) -> SymbolOccurrence
|
|
133
132
|
def renameable_occurrence(path, position)
|
|
134
133
|
occurrence = occurrence_at(path, position)
|
|
135
134
|
unless occurrence && %i[rule terminal parameter].include?(occurrence.kind) &&
|
|
@@ -232,7 +231,8 @@ module Ibex
|
|
|
232
231
|
lines << "Display: #{data[:display]}" if data[:display]
|
|
233
232
|
lines << "Type: `#{data[:type]}`" if data[:type]
|
|
234
233
|
if (precedence = data[:precedence])
|
|
235
|
-
|
|
234
|
+
precedence_data = precedence #: Hash[Symbol, symbol_data_value]
|
|
235
|
+
lines << "Precedence: #{precedence_data[:associativity]} level #{precedence_data[:level]}"
|
|
236
236
|
end
|
|
237
237
|
lines.join("\n\n")
|
|
238
238
|
end
|
|
@@ -14,8 +14,8 @@ module Ibex
|
|
|
14
14
|
@occurrences = [] #: Array[SymbolOccurrence]
|
|
15
15
|
@documents = {} #: Hash[String, Frontend::SourceDocument]
|
|
16
16
|
@global_kinds = {} #: Hash[String, Symbol]
|
|
17
|
-
@rule_data = {} #: Hash[String,
|
|
18
|
-
@terminal_data = Hash.new { |hash, key| hash[key] = {} } #: Hash[String,
|
|
17
|
+
@rule_data = {} #: Hash[String, symbol_data]
|
|
18
|
+
@terminal_data = Hash.new { |hash, key| hash[key] = {} } #: Hash[String, symbol_data]
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
# @rbs () -> [Array[SymbolOccurrence], Hash[String, Frontend::SourceDocument]]
|
|
@@ -85,21 +85,25 @@ module Ibex
|
|
|
85
85
|
# @rbs (String path, Array[Frontend::Token] tokens, Frontend::AST::Include declaration) -> void
|
|
86
86
|
def collect_include(path, tokens, declaration)
|
|
87
87
|
token = tokens.find { |candidate| candidate.type == :literal }
|
|
88
|
-
|
|
88
|
+
span = token&.span
|
|
89
|
+
return unless span
|
|
89
90
|
|
|
90
91
|
target = canonical_include_target(declaration)
|
|
91
92
|
return unless target
|
|
92
93
|
|
|
93
94
|
add_occurrence(
|
|
94
95
|
name: declaration.path, kind: :include, role: :reference, key: [:include, target],
|
|
95
|
-
path: path, span:
|
|
96
|
+
path: path, span: span, data: { target: target }
|
|
96
97
|
)
|
|
97
98
|
end
|
|
98
99
|
|
|
99
100
|
# @rbs (String path, Frontend::SourceDocument document, Frontend::AST::Rule rule) -> void
|
|
100
101
|
def collect_rule_definition(path, document, rule)
|
|
101
102
|
token = token_at(document, rule.loc, rule.lhs)
|
|
102
|
-
|
|
103
|
+
span = token&.span
|
|
104
|
+
return unless span
|
|
105
|
+
|
|
106
|
+
lhs_token = token #: Frontend::Token
|
|
103
107
|
|
|
104
108
|
@global_kinds[rule.lhs] ||= :rule
|
|
105
109
|
signature = "#{rule.lhs}#{parameter_signature(rule.parameters)}"
|
|
@@ -113,9 +117,9 @@ module Ibex
|
|
|
113
117
|
@rule_data[rule.lhs] ||= data
|
|
114
118
|
add_occurrence(
|
|
115
119
|
name: rule.lhs, kind: :rule, role: :definition, key: global_key(rule.lhs),
|
|
116
|
-
path: path, span:
|
|
120
|
+
path: path, span: span, data: data
|
|
117
121
|
)
|
|
118
|
-
collect_parameters(path, document, rule,
|
|
122
|
+
collect_parameters(path, document, rule, lhs_token)
|
|
119
123
|
end
|
|
120
124
|
|
|
121
125
|
# @rbs (String path, Frontend::SourceDocument document, Frontend::AST::Rule rule,
|
|
@@ -125,11 +129,12 @@ module Ibex
|
|
|
125
129
|
|
|
126
130
|
rule_id = lhs_token.span&.start_byte || 0
|
|
127
131
|
rule.parameters.zip(parameter_tokens(document, lhs_token)).each do |parameter, token|
|
|
128
|
-
|
|
132
|
+
span = token&.span
|
|
133
|
+
next unless span
|
|
129
134
|
|
|
130
135
|
add_occurrence(
|
|
131
136
|
name: parameter, kind: :parameter, role: :definition,
|
|
132
|
-
key: parameter_key(path, rule_id, parameter), path: path, span:
|
|
137
|
+
key: parameter_key(path, rule_id, parameter), path: path, span: span,
|
|
133
138
|
data: { rule: rule.lhs }
|
|
134
139
|
)
|
|
135
140
|
end
|
|
@@ -205,18 +210,19 @@ module Ibex
|
|
|
205
210
|
|
|
206
211
|
# @rbs (String path, Frontend::Token token, String name) -> void
|
|
207
212
|
def add_global_reference(path, token, name)
|
|
208
|
-
|
|
213
|
+
span = token.span
|
|
214
|
+
return unless span
|
|
209
215
|
|
|
210
216
|
kind = @global_kinds[name] || :terminal
|
|
211
217
|
data = symbol_data(kind, name)
|
|
212
218
|
add_occurrence(name: name, kind: kind, role: :reference, key: global_key(name),
|
|
213
|
-
path: path, span:
|
|
219
|
+
path: path, span: span, data: data)
|
|
214
220
|
end
|
|
215
221
|
|
|
216
|
-
# @rbs (Symbol kind, String name) ->
|
|
222
|
+
# @rbs (Symbol kind, String name) -> symbol_data
|
|
217
223
|
def symbol_data(kind, name)
|
|
218
224
|
data = kind == :rule ? @rule_data[name] : @terminal_data[name]
|
|
219
|
-
empty = {} #:
|
|
225
|
+
empty = {} #: symbol_data
|
|
220
226
|
data || empty
|
|
221
227
|
end
|
|
222
228
|
|
|
@@ -226,25 +232,29 @@ module Ibex
|
|
|
226
232
|
names.each do |name|
|
|
227
233
|
index = remaining.index { |token| token.value == name }
|
|
228
234
|
token = index && remaining.delete_at(index)
|
|
229
|
-
|
|
235
|
+
span = token&.span
|
|
236
|
+
next unless span
|
|
230
237
|
|
|
231
238
|
@global_kinds[name] ||= kind
|
|
232
239
|
add_occurrence(name: name, kind: kind, role: role, key: global_key(name),
|
|
233
|
-
path: path, span:
|
|
240
|
+
path: path, span: span, data: @terminal_data[name])
|
|
234
241
|
end
|
|
235
242
|
end
|
|
236
243
|
|
|
237
|
-
# @rbs (
|
|
238
|
-
|
|
239
|
-
|
|
244
|
+
# @rbs (name: String, kind: Symbol, role: Symbol, key: symbol_key, path: String,
|
|
245
|
+
# span: Frontend::SourceSpan, data: symbol_data) -> void
|
|
246
|
+
def add_occurrence(name:, kind:, role:, key:, path:, span:, data:)
|
|
247
|
+
@occurrences << SymbolOccurrence.new(
|
|
248
|
+
name: name, kind: kind, role: role, key: key, path: path, span: span, data: data
|
|
249
|
+
)
|
|
240
250
|
end
|
|
241
251
|
|
|
242
|
-
# @rbs (String name) ->
|
|
252
|
+
# @rbs (String name) -> symbol_key
|
|
243
253
|
def global_key(name)
|
|
244
254
|
[:symbol, name]
|
|
245
255
|
end
|
|
246
256
|
|
|
247
|
-
# @rbs (String path, Integer rule_id, String name) ->
|
|
257
|
+
# @rbs (String path, Integer rule_id, String name) -> symbol_key
|
|
248
258
|
def parameter_key(path, rule_id, name)
|
|
249
259
|
[:parameter, path, rule_id, name]
|
|
250
260
|
end
|
|
@@ -2,15 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
module Ibex
|
|
4
4
|
module LSP
|
|
5
|
+
# @rbs!
|
|
6
|
+
# type symbol_key = [:symbol, String] | [:parameter, String, Integer, String] | [:include, String]
|
|
7
|
+
# type symbol_data_value = String | Symbol | Integer | bool | nil | Array[String] |
|
|
8
|
+
# Hash[Symbol, symbol_data_value]
|
|
9
|
+
# type symbol_data = Hash[Symbol, symbol_data_value]
|
|
10
|
+
|
|
5
11
|
# A source-backed grammar symbol definition or reference.
|
|
6
12
|
SymbolOccurrence = Struct.new(
|
|
7
13
|
:name, #: String
|
|
8
14
|
:kind, #: Symbol
|
|
9
15
|
:role, #: Symbol
|
|
10
|
-
:key, #:
|
|
16
|
+
:key, #: symbol_key
|
|
11
17
|
:path, #: String
|
|
12
18
|
:span, #: Frontend::SourceSpan
|
|
13
|
-
:data, #:
|
|
19
|
+
:data, #: symbol_data
|
|
14
20
|
keyword_init: true
|
|
15
21
|
)
|
|
16
22
|
end
|
data/lib/ibex/lsp/transport.rb
CHANGED
|
@@ -4,16 +4,26 @@ module Ibex
|
|
|
4
4
|
module LSP
|
|
5
5
|
# Reads and writes bounded LSP JSON-RPC messages over Content-Length framing.
|
|
6
6
|
class Transport
|
|
7
|
+
# @rbs!
|
|
8
|
+
# interface _Input
|
|
9
|
+
# def read: (Integer length) -> String?
|
|
10
|
+
# def readpartial: (Integer length) -> String
|
|
11
|
+
# end
|
|
12
|
+
# interface _Output
|
|
13
|
+
# def write: (String value) -> Object?
|
|
14
|
+
# def flush: () -> Object?
|
|
15
|
+
# end
|
|
16
|
+
|
|
7
17
|
HEADER_SEPARATOR = "\r\n\r\n"
|
|
8
18
|
|
|
9
|
-
# @rbs (
|
|
19
|
+
# @rbs (_Input input, _Output output) -> void
|
|
10
20
|
def initialize(input, output)
|
|
11
21
|
@input = input
|
|
12
22
|
@output = output
|
|
13
23
|
@buffer = String.new(encoding: Encoding::BINARY)
|
|
14
24
|
end
|
|
15
25
|
|
|
16
|
-
# @rbs () ->
|
|
26
|
+
# @rbs () -> LSP::lsp_object?
|
|
17
27
|
def read_message
|
|
18
28
|
header = read_header
|
|
19
29
|
return unless header
|
|
@@ -28,7 +38,7 @@ module Ibex
|
|
|
28
38
|
raise ProtocolError.new("malformed JSON: #{e.message}", code: -32_700)
|
|
29
39
|
end
|
|
30
40
|
|
|
31
|
-
# @rbs (
|
|
41
|
+
# @rbs (LSP::lsp_object message) -> void
|
|
32
42
|
def write_message(message)
|
|
33
43
|
body = JSON.generate(message)
|
|
34
44
|
if body.bytesize > Limits::MAX_OUTPUT_BYTES
|
data/lib/ibex/lsp/workspace.rb
CHANGED
|
@@ -17,7 +17,7 @@ module Ibex
|
|
|
17
17
|
# @rbs (String uri, ?allow_missing: bool) -> String
|
|
18
18
|
def path(uri, allow_missing: true)
|
|
19
19
|
parsed = parse_file_uri(uri)
|
|
20
|
-
decoded = decode_path(parsed.path)
|
|
20
|
+
decoded = decode_path(parsed.path || raise(ArgumentError, "file URI must contain an absolute path"))
|
|
21
21
|
|
|
22
22
|
canonical = @loader.canonical_path(decoded, allow_missing: allow_missing)
|
|
23
23
|
return canonical if root_for(canonical)
|
|
@@ -48,11 +48,12 @@ module Ibex
|
|
|
48
48
|
private
|
|
49
49
|
|
|
50
50
|
# URI is a stdlib boundary whose implementation class varies by scheme.
|
|
51
|
-
#
|
|
51
|
+
# URI parsing returns a scheme-specific URI::Generic subclass.
|
|
52
|
+
# @rbs (String uri) -> URI::Generic
|
|
52
53
|
def parse_file_uri(uri)
|
|
53
54
|
validate_raw_authority!(uri)
|
|
54
55
|
parsed = URI.parse(uri)
|
|
55
|
-
path = parsed.path
|
|
56
|
+
path = parsed.path || raise(ArgumentError, "file URI must contain an absolute path")
|
|
56
57
|
local_host = parsed.host.nil? || parsed.host.empty? || parsed.host.casecmp?("localhost")
|
|
57
58
|
unless parsed.scheme == "file" && local_host &&
|
|
58
59
|
parsed.query.nil? && parsed.fragment.nil? && path&.start_with?("/")
|
|
@@ -77,7 +78,7 @@ module Ibex
|
|
|
77
78
|
# @rbs (String uri) -> String
|
|
78
79
|
def canonical_root(uri)
|
|
79
80
|
parsed = parse_file_uri(uri)
|
|
80
|
-
decoded = decode_path(parsed.path)
|
|
81
|
+
decoded = decode_path(parsed.path || raise(ArgumentError, "file URI must contain an absolute path"))
|
|
81
82
|
canonical = File.realpath(decoded)
|
|
82
83
|
unless File.directory?(canonical)
|
|
83
84
|
raise ProtocolError.new("workspace root is not a directory: #{uri}", code: -32_602)
|
|
@@ -8,7 +8,7 @@ module Ibex
|
|
|
8
8
|
WINDOWS_ABSOLUTE = %r{\A(?:[A-Za-z]:[\\/]|\\\\)} #: Regexp
|
|
9
9
|
|
|
10
10
|
# @rbs!
|
|
11
|
-
# type lsp_diagnostic =
|
|
11
|
+
# type lsp_diagnostic = lsp_object
|
|
12
12
|
# type analyzed_document = {
|
|
13
13
|
# source: String,
|
|
14
14
|
# document: Frontend::SourceDocument?,
|
data/lib/ibex/lsp.rb
CHANGED
|
@@ -18,6 +18,7 @@ require_relative "lsp/symbol_index_source_queries"
|
|
|
18
18
|
require_relative "lsp/symbol_index_precedence_references"
|
|
19
19
|
require_relative "lsp/symbol_index_builder"
|
|
20
20
|
require_relative "lsp/symbol_index"
|
|
21
|
+
require_relative "lsp/parser_configuration_assistance"
|
|
21
22
|
require_relative "lsp/request_support"
|
|
22
23
|
require_relative "lsp/initialization_handlers"
|
|
23
24
|
require_relative "lsp/document_handlers"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"messages": {
|
|
4
|
+
"cli.error": "%{detail}",
|
|
5
|
+
"diagnostic.frontend.lexical_error": "%{detail}",
|
|
6
|
+
"diagnostic.frontend.syntax_error": "%{detail}",
|
|
7
|
+
"diagnostic.frontend.resolution_error": "%{detail}",
|
|
8
|
+
"diagnostic.generic": "%{detail}",
|
|
9
|
+
"label.warning": "warning",
|
|
10
|
+
"label.warning_as_error": "warning treated as error",
|
|
11
|
+
"warning.undeclared_terminal": "undeclared terminal %{symbol}",
|
|
12
|
+
"warning.unused_terminal": "unused terminal %{symbol}",
|
|
13
|
+
"warning.unused_precedence": "unused precedence %{symbol}",
|
|
14
|
+
"warning.unreachable_terminal": "declared terminal %{symbol} is unreachable",
|
|
15
|
+
"warning.unreachable_nonterminal": "unreachable nonterminal %{symbol}",
|
|
16
|
+
"warning.duplicate_production": "duplicate production %{production} (first defined as %{original})",
|
|
17
|
+
"warning.implicit_empty": "implicit empty alternative; write %%empty to document intent",
|
|
18
|
+
"warning.empty_language": "start symbol %{symbol} derives no terminal sentence",
|
|
19
|
+
"warning.lexer_redos": "lexer pattern may exhibit excessive backtracking",
|
|
20
|
+
"warning.lexer_redos_symbol": "lexer pattern for %{symbol} may exhibit excessive backtracking",
|
|
21
|
+
"conflict.shift_reduce_expected": "%{actual} shift/reduce conflicts; expected %{expected}",
|
|
22
|
+
"conflict.reduce_reduce_expected": "%{actual} reduce/reduce conflicts; expected %{expected}",
|
|
23
|
+
"conflict.reduce_reduce": "%{actual} reduce/reduce conflicts",
|
|
24
|
+
"conflict.treated_as_error": "%{detail}; conflict treated as error",
|
|
25
|
+
"conflict.count": "%{count} %{kind} conflict%{plural}",
|
|
26
|
+
"note.ielr": "note: --algorithm=ielr avoids %{avoided}; consider --algorithm=ielr"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"messages": {
|
|
4
|
+
"cli.error": "エラー: %{detail}",
|
|
5
|
+
"diagnostic.frontend.lexical_error": "字句エラー: %{detail}",
|
|
6
|
+
"diagnostic.frontend.syntax_error": "構文エラー: %{detail}",
|
|
7
|
+
"diagnostic.frontend.resolution_error": "解決エラー: %{detail}",
|
|
8
|
+
"diagnostic.generic": "診断: %{detail}",
|
|
9
|
+
"label.warning": "警告",
|
|
10
|
+
"label.warning_as_error": "エラーとして扱われた警告",
|
|
11
|
+
"warning.undeclared_terminal": "未宣言の終端記号 %{symbol}",
|
|
12
|
+
"warning.unused_terminal": "未使用の終端記号 %{symbol}",
|
|
13
|
+
"warning.unused_precedence": "未使用の優先順位 %{symbol}",
|
|
14
|
+
"warning.unreachable_terminal": "宣言された終端記号 %{symbol} に到達できません",
|
|
15
|
+
"warning.unreachable_nonterminal": "非終端記号 %{symbol} に到達できません",
|
|
16
|
+
"warning.duplicate_production": "生成規則 %{production} は重複しています(最初の定義: %{original})",
|
|
17
|
+
"warning.implicit_empty": "暗黙の空選択肢です。意図を示すには %%empty を記述してください",
|
|
18
|
+
"warning.empty_language": "開始記号 %{symbol} は終端記号列を導出しません",
|
|
19
|
+
"warning.lexer_redos": "字句パターンで過大なバックトラックが発生する可能性があります",
|
|
20
|
+
"warning.lexer_redos_symbol": "%{symbol} の字句パターンで過大なバックトラックが発生する可能性があります",
|
|
21
|
+
"conflict.shift_reduce_expected": "shift/reduce 競合は %{actual} 件です(期待値: %{expected})",
|
|
22
|
+
"conflict.reduce_reduce_expected": "reduce/reduce 競合は %{actual} 件です(期待値: %{expected})",
|
|
23
|
+
"conflict.reduce_reduce": "reduce/reduce 競合が %{actual} 件あります",
|
|
24
|
+
"conflict.treated_as_error": "%{detail}(競合をエラーとして扱いました)",
|
|
25
|
+
"conflict.count": "%{kind} 競合 %{count} 件%{plural}",
|
|
26
|
+
"note.ielr": "注記: --algorithm=ielr により %{avoided} を回避できます。--algorithm=ielr を検討してください"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
module Ibex
|
|
7
|
+
# Immutable built-in diagnostic translations, separate from user E00xx
|
|
8
|
+
# sentence-keyed parser error catalogs.
|
|
9
|
+
module Messages
|
|
10
|
+
ROOT = File.expand_path("messages", __dir__ || raise("message catalog directory is unavailable")) #: String
|
|
11
|
+
LANGUAGES = %w[en ja].freeze #: Array[String]
|
|
12
|
+
|
|
13
|
+
# @rbs (String? requested) -> String
|
|
14
|
+
def language(requested)
|
|
15
|
+
candidate = requested.to_s.downcase.tr("_", "-").split("-").first
|
|
16
|
+
LANGUAGES.include?(candidate) ? candidate : "en"
|
|
17
|
+
end
|
|
18
|
+
module_function :language
|
|
19
|
+
|
|
20
|
+
# @rbs (String id, ?language: String, **Object? values) -> String
|
|
21
|
+
def translate(id, language: "en", **values)
|
|
22
|
+
selected = catalog(self.language(language))
|
|
23
|
+
template = selected[id] || catalog("en").fetch(id) do
|
|
24
|
+
raise Ibex::Error, "(messages):1:1: unknown built-in message id #{id.inspect}"
|
|
25
|
+
end
|
|
26
|
+
template % values.transform_keys(&:to_sym)
|
|
27
|
+
rescue KeyError => e
|
|
28
|
+
raise Ibex::Error, "(messages):1:1: missing interpolation for #{id.inspect}: #{e.message}"
|
|
29
|
+
end
|
|
30
|
+
module_function :translate
|
|
31
|
+
|
|
32
|
+
# @rbs (String id) -> bool
|
|
33
|
+
def known?(id)
|
|
34
|
+
catalog("en").key?(id)
|
|
35
|
+
end
|
|
36
|
+
module_function :known?
|
|
37
|
+
|
|
38
|
+
# @rbs (String language) -> Hash[String, String]
|
|
39
|
+
def catalog(language)
|
|
40
|
+
@catalogs ||= {} #: Hash[String, Hash[String, String]]
|
|
41
|
+
@catalogs[language] ||= load_catalog(language)
|
|
42
|
+
end
|
|
43
|
+
module_function :catalog
|
|
44
|
+
|
|
45
|
+
# @rbs (String language) -> Hash[String, String]
|
|
46
|
+
def load_catalog(language)
|
|
47
|
+
path = File.join(ROOT, "#{language}.yml")
|
|
48
|
+
document = JSON.parse(File.binread(path))
|
|
49
|
+
unless document.is_a?(Hash) && document["version"] == 1 && document["messages"].is_a?(Hash)
|
|
50
|
+
raise Ibex::Error, "#{path}:1:1: invalid built-in message catalog"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
document.fetch("messages").to_h do |id, value|
|
|
54
|
+
unless id.is_a?(String) && value.is_a?(String)
|
|
55
|
+
raise Ibex::Error, "#{path}:1:1: message ids and templates must be strings"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
[id.freeze, value.freeze]
|
|
59
|
+
end.freeze
|
|
60
|
+
rescue Errno::ENOENT => e
|
|
61
|
+
raise Ibex::Error, "#{path}:1:1: cannot read built-in message catalog: #{e.message}"
|
|
62
|
+
rescue JSON::ParserError => e
|
|
63
|
+
raise Ibex::Error, "#{path}:1:1: invalid JSON-compatible YAML: #{e.message}"
|
|
64
|
+
end
|
|
65
|
+
module_function :load_catalog
|
|
66
|
+
private_class_method :load_catalog
|
|
67
|
+
end
|
|
68
|
+
end
|
data/lib/ibex/metrics.rb
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
require "set"
|
|
5
|
+
|
|
6
|
+
module Ibex
|
|
7
|
+
# Deterministic structural metrics over normalized Grammar and Automaton IR.
|
|
8
|
+
class Metrics
|
|
9
|
+
# @rbs!
|
|
10
|
+
# type report_value = String | Integer | Float | Array[report_value] | Hash[Symbol, report_value]
|
|
11
|
+
|
|
12
|
+
# @rbs (IR::Automaton automaton) -> void
|
|
13
|
+
def initialize(automaton)
|
|
14
|
+
@automaton = automaton
|
|
15
|
+
@grammar = automaton.grammar
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @rbs () -> Hash[Symbol, report_value]
|
|
19
|
+
def to_h
|
|
20
|
+
{
|
|
21
|
+
ibex_report: "metrics", schema_version: 1,
|
|
22
|
+
algorithm: @automaton.algorithm,
|
|
23
|
+
grammar_digest: @automaton.grammar_digest,
|
|
24
|
+
symbols: symbol_metrics,
|
|
25
|
+
grammar: grammar_metrics,
|
|
26
|
+
automaton: automaton_metrics
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# @rbs () -> Hash[Symbol, Integer]
|
|
33
|
+
def symbol_metrics
|
|
34
|
+
{ terminals: @grammar.terminals.length, nonterminals: @grammar.nonterminals.length }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @rbs () -> Hash[Symbol, report_value]
|
|
38
|
+
def grammar_metrics
|
|
39
|
+
rule_counts = @grammar.productions.group_by(&:lhs).transform_values(&:length)
|
|
40
|
+
{
|
|
41
|
+
rules: rule_counts.length,
|
|
42
|
+
alternatives: @grammar.productions.length,
|
|
43
|
+
average_alternatives_per_rule: average(rule_counts.values),
|
|
44
|
+
maximum_branching: rule_counts.values.max || 0,
|
|
45
|
+
epsilon_productions: @grammar.productions.count { |production| production.rhs.empty? },
|
|
46
|
+
recursive_nonterminals: recursive_nonterminal_ids.map { |id| symbol_name(id) }.sort,
|
|
47
|
+
recursion_component_depth: recursion_component_depth,
|
|
48
|
+
warnings: @grammar.warnings.length
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @rbs () -> Hash[Symbol, report_value]
|
|
53
|
+
def automaton_metrics
|
|
54
|
+
{
|
|
55
|
+
states: @automaton.states.length,
|
|
56
|
+
transitions: @automaton.states.sum { |state| state.transitions.length },
|
|
57
|
+
action_cells: @automaton.states.sum { |state| state.actions.length },
|
|
58
|
+
goto_cells: @automaton.states.sum { |state| state.gotos.length },
|
|
59
|
+
default_reductions: @automaton.states.count(&:default_action),
|
|
60
|
+
conflicts: {
|
|
61
|
+
shift_reduce: @automaton.conflict_summary.fetch(:sr),
|
|
62
|
+
precedence_resolved_shift_reduce: @automaton.conflict_summary.fetch(:resolved_sr),
|
|
63
|
+
reduce_reduce: @automaton.conflict_summary.fetch(:rr)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @rbs (Array[Integer] values) -> Float
|
|
69
|
+
def average(values)
|
|
70
|
+
return 0.0 if values.empty?
|
|
71
|
+
|
|
72
|
+
values.sum.fdiv(values.length).round(6)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @rbs () -> Hash[Integer, Array[Integer]]
|
|
76
|
+
def dependency_graph
|
|
77
|
+
@dependency_graph ||= begin
|
|
78
|
+
graph = {} #: Hash[Integer, Array[Integer]]
|
|
79
|
+
@grammar.nonterminals.each { |symbol| graph[symbol.id] = [] }
|
|
80
|
+
@grammar.productions.each do |production|
|
|
81
|
+
production.rhs.each do |id|
|
|
82
|
+
symbol = @grammar.symbol_by_id(id)
|
|
83
|
+
graph.fetch(production.lhs) << id if symbol&.nonterminal?
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
graph.transform_values { |targets| targets.uniq.sort }
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# @rbs () -> Hash[Integer, Set[Integer]]
|
|
91
|
+
def reachability
|
|
92
|
+
@reachability ||= dependency_graph.to_h do |source, _targets|
|
|
93
|
+
found = Set[source]
|
|
94
|
+
queue = [source]
|
|
95
|
+
cursor = 0
|
|
96
|
+
while cursor < queue.length
|
|
97
|
+
dependency_graph.fetch(queue.fetch(cursor)).each do |target|
|
|
98
|
+
next if found.include?(target)
|
|
99
|
+
|
|
100
|
+
found << target
|
|
101
|
+
queue << target
|
|
102
|
+
end
|
|
103
|
+
cursor += 1
|
|
104
|
+
end
|
|
105
|
+
[source, found]
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# @rbs () -> Array[Array[Integer]]
|
|
110
|
+
def recursion_components
|
|
111
|
+
remaining = dependency_graph.keys.sort
|
|
112
|
+
components = [] #: Array[Array[Integer]]
|
|
113
|
+
until remaining.empty?
|
|
114
|
+
source = remaining.fetch(0)
|
|
115
|
+
component = remaining.select do |candidate|
|
|
116
|
+
reachability.fetch(source).include?(candidate) && reachability.fetch(candidate).include?(source)
|
|
117
|
+
end
|
|
118
|
+
components << component
|
|
119
|
+
remaining -= component
|
|
120
|
+
end
|
|
121
|
+
components
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @rbs () -> Array[Integer]
|
|
125
|
+
def recursive_nonterminal_ids
|
|
126
|
+
recursion_components.flat_map do |component|
|
|
127
|
+
next component if component.length > 1
|
|
128
|
+
|
|
129
|
+
id = component.fetch(0)
|
|
130
|
+
dependency_graph.fetch(id).include?(id) ? component : []
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Longest path after collapsing mutually recursive nonterminals.
|
|
135
|
+
# @rbs () -> Integer
|
|
136
|
+
def recursion_component_depth
|
|
137
|
+
components = recursion_components
|
|
138
|
+
component_for = {} #: Hash[Integer, Integer]
|
|
139
|
+
components.each_with_index { |ids, index| ids.each { |id| component_for[id] = index } }
|
|
140
|
+
edges = Array.new(components.length) { Set.new } #: Array[Set[Integer]]
|
|
141
|
+
dependency_graph.each do |source, targets|
|
|
142
|
+
targets.each do |target|
|
|
143
|
+
from = component_for.fetch(source)
|
|
144
|
+
to = component_for.fetch(target)
|
|
145
|
+
edges.fetch(from) << to unless from == to
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
longest_dag_path(edges)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# @rbs (Array[Set[Integer]] edges) -> Integer
|
|
152
|
+
def longest_dag_path(edges)
|
|
153
|
+
indegree = Array.new(edges.length, 0)
|
|
154
|
+
edges.each { |targets| targets.each { |target| indegree[target] += 1 } }
|
|
155
|
+
depths = Array.new(edges.length, 1)
|
|
156
|
+
queue = indegree.each_index.select { |index| indegree[index].zero? }
|
|
157
|
+
cursor = 0
|
|
158
|
+
while cursor < queue.length
|
|
159
|
+
source = queue.fetch(cursor)
|
|
160
|
+
edges.fetch(source).each do |target|
|
|
161
|
+
depths[target] = [depths[target], depths[source] + 1].max
|
|
162
|
+
indegree[target] -= 1
|
|
163
|
+
queue << target if indegree[target].zero?
|
|
164
|
+
end
|
|
165
|
+
cursor += 1
|
|
166
|
+
end
|
|
167
|
+
depths.max || 0
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# @rbs (Integer id) -> String
|
|
171
|
+
def symbol_name(id)
|
|
172
|
+
@grammar.symbol_by_id(id)&.name || id.to_s
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
@@ -28,6 +28,7 @@ module Ibex
|
|
|
28
28
|
@on_error_reduce_locations = {} #: Hash[String, Frontend::Location]
|
|
29
29
|
@grammar_tests = [] #: Array[IR::grammar_test]
|
|
30
30
|
@lexer_declaration = nil #: Frontend::AST::Lexer?
|
|
31
|
+
@parser_configuration = nil #: Frontend::AST::ParserConfiguration?
|
|
31
32
|
@node_shapes = {} #: Hash[String, Array[String]]
|
|
32
33
|
@ast.declarations.each { |declaration| read_declaration(declaration) }
|
|
33
34
|
end
|
|
@@ -46,6 +47,7 @@ module Ibex
|
|
|
46
47
|
when Frontend::AST::Lexer
|
|
47
48
|
fail_at(declaration.loc, "duplicate lexer declaration") if @lexer_declaration
|
|
48
49
|
@lexer_declaration = declaration
|
|
50
|
+
when Frontend::AST::ParserConfiguration then read_parser_configuration(declaration)
|
|
49
51
|
when Frontend::AST::Convert then read_conversions(declaration)
|
|
50
52
|
when Frontend::AST::DisplayName, Frontend::AST::SemanticType, Frontend::AST::Parameter, Frontend::AST::Printer
|
|
51
53
|
read_extended_declaration(declaration)
|