ibex 0.1.0 → 0.2.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 +247 -104
- data/docs/architecture.md +322 -28
- data/docs/cst-migration.md +107 -0
- data/docs/cst.md +213 -0
- data/docs/development.md +129 -0
- data/docs/editor-setup.md +25 -0
- data/docs/error-ux.md +60 -0
- data/docs/grammar-reference.md +458 -18
- data/docs/lexer-migration.md +51 -0
- data/docs/racc-migration.md +34 -6
- data/docs/release-readiness.md +163 -0
- data/docs/stability.md +124 -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/sets.rb +5 -4
- data/lib/ibex/artifact_set.rb +63 -0
- data/lib/ibex/cli/ambiguity.rb +66 -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 +116 -0
- data/lib/ibex/cli/documentation.rb +67 -0
- data/lib/ibex/cli/error_messages.rb +177 -0
- data/lib/ibex/cli/explain.rb +76 -0
- data/lib/ibex/cli/formatting.rb +386 -0
- data/lib/ibex/cli/generation_artifacts.rb +138 -0
- data/lib/ibex/cli/generation_error_messages.rb +39 -0
- data/lib/ibex/cli/grammar_tests.rb +122 -0
- data/lib/ibex/cli/ir_tools.rb +184 -0
- data/lib/ibex/cli/lsp.rb +33 -0
- data/lib/ibex/cli/outputs.rb +91 -8
- data/lib/ibex/cli/racc_migration.rb +87 -0
- data/lib/ibex/cli/samples.rb +92 -0
- data/lib/ibex/cli/watch.rb +103 -0
- data/lib/ibex/cli.rb +506 -37
- data/lib/ibex/codegen/action_locations.rb +103 -0
- data/lib/ibex/codegen/action_method_source.rb +210 -0
- data/lib/ibex/codegen/action_source.rb +118 -0
- data/lib/ibex/codegen/ambiguity.rb +173 -0
- data/lib/ibex/codegen/cst_metadata.rb +171 -0
- data/lib/ibex/codegen/documentation.rb +170 -0
- data/lib/ibex/codegen/explain.rb +312 -0
- data/lib/ibex/codegen/generated_action_abi.rb +288 -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 +323 -2
- data/lib/ibex/codegen/report.rb +46 -6
- data/lib/ibex/codegen/ruby.rb +334 -59
- data/lib/ibex/codegen/ruby_actions.rb +143 -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 +90 -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/coverage/collector.rb +188 -0
- data/lib/ibex/coverage/event_stream.rb +97 -0
- data/lib/ibex/coverage/report.rb +259 -0
- data/lib/ibex/coverage/runtime_event_validator.rb +160 -0
- data/lib/ibex/coverage.rb +13 -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/frontend/ast.rb +145 -6
- data/lib/ibex/frontend/bootstrap_parser.rb +47 -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 +407 -0
- data/lib/ibex/frontend/generated_parser.rb +614 -190
- data/lib/ibex/frontend/generated_parser_base.rb +164 -30
- data/lib/ibex/frontend/generated_parser_includes.rb +61 -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 +247 -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/regenerator.rb +26 -1
- data/lib/ibex/frontend/resolution.rb +69 -0
- data/lib/ibex/frontend/resolver.rb +217 -0
- data/lib/ibex/frontend/rule_documentation.rb +103 -0
- data/lib/ibex/frontend/source_cursor.rb +132 -8
- 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 +81 -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 +216 -26
- 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 +8 -3
- data/lib/ibex/frontend.rb +13 -2
- data/lib/ibex/generation_input.rb +57 -0
- data/lib/ibex/generation_manifest.rb +200 -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 +38 -5
- data/lib/ibex/ir/grammar_ir.rb +137 -24
- data/lib/ibex/ir/lexer_ir.rb +76 -0
- data/lib/ibex/ir/migration.rb +120 -0
- data/lib/ibex/ir/serialize.rb +110 -19
- data/lib/ibex/ir/validator/automaton.rb +345 -0
- data/lib/ibex/ir/validator/base.rb +129 -0
- data/lib/ibex/ir/validator/grammar.rb +604 -0
- data/lib/ibex/ir/validator/lexer.rb +113 -0
- data/lib/ibex/ir/validator.rb +62 -0
- data/lib/ibex/ir.rb +57 -4
- data/lib/ibex/lalr/build_metrics.rb +23 -0
- data/lib/ibex/lalr/builder.rb +379 -52
- data/lib/ibex/lalr/conflict.rb +1 -0
- data/lib/ibex/lalr/conflict_search.rb +11 -5
- data/lib/ibex/lalr/counterexample.rb +20 -5
- data/lib/ibex/lalr/direct_lookaheads.rb +236 -0
- data/lib/ibex/lalr/ielr_partition.rb +152 -0
- data/lib/ibex/lalr/on_error_reductions.rb +74 -0
- data/lib/ibex/lalr.rb +7 -0
- data/lib/ibex/location.rb +129 -0
- data/lib/ibex/lsp/document_handlers.rb +66 -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 +78 -0
- data/lib/ibex/lsp/navigation_handlers.rb +56 -0
- data/lib/ibex/lsp/position_codec.rb +109 -0
- data/lib/ibex/lsp/protocol_error.rb +33 -0
- data/lib/ibex/lsp/request_handlers.rb +45 -0
- data/lib/ibex/lsp/request_support.rb +87 -0
- data/lib/ibex/lsp/server.rb +146 -0
- data/lib/ibex/lsp/symbol_index.rb +241 -0
- data/lib/ibex/lsp/symbol_index_builder.rb +267 -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 +17 -0
- data/lib/ibex/lsp/transport.rb +118 -0
- data/lib/ibex/lsp/workspace.rb +127 -0
- data/lib/ibex/lsp/workspace_analyzer.rb +199 -0
- data/lib/ibex/lsp.rb +32 -0
- data/lib/ibex/normalize/declarations.rb +140 -7
- data/lib/ibex/normalize/diagnostics.rb +50 -5
- data/lib/ibex/normalize/expander.rb +59 -55
- data/lib/ibex/normalize/expression.rb +60 -39
- data/lib/ibex/normalize/inline_expansion.rb +414 -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 +69 -0
- data/lib/ibex/normalize/parameter_lowering.rb +126 -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 +199 -0
- data/lib/ibex/normalize/recovery_declarations.rb +84 -0
- data/lib/ibex/normalize.rb +179 -14
- 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 +94 -0
- data/lib/ibex/racc_migration.rb +12 -0
- data/lib/ibex/rake_task.rb +116 -0
- data/lib/ibex/samples.rb +186 -0
- data/lib/ibex/table_simulation/result.rb +51 -0
- data/lib/ibex/table_simulation/simulator.rb +253 -0
- data/lib/ibex/table_simulation/step.rb +60 -0
- data/lib/ibex/table_simulation/text.rb +31 -0
- data/lib/ibex/table_simulation.rb +13 -0
- data/lib/ibex/tables.rb +9 -70
- data/lib/ibex/version.rb +1 -1
- data/lib/ibex/watch/runner.rb +172 -0
- data/lib/ibex/watch/source_snapshot.rb +93 -0
- data/lib/ibex/watch.rb +11 -0
- data/lib/ibex.rb +25 -1
- data/schema/automaton-ir-v1.schema.json +401 -0
- data/schema/automaton-ir-v2.schema.json +58 -0
- data/schema/benchmark-v1.schema.json +212 -0
- data/schema/benchmark-v2.schema.json +61 -0
- data/schema/cst-v1.json +170 -0
- data/schema/error-ux-v1.schema.json +258 -0
- data/schema/explain-v1.schema.json +433 -0
- data/schema/frontend-diagnostics-v1.schema.json +154 -0
- data/schema/generation-manifest-v1.schema.json +115 -0
- data/schema/grammar-ir-v1.schema.json +426 -0
- data/schema/grammar-ir-v2.schema.json +779 -0
- data/schema/lexer-ir-v1.schema.json +215 -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/runtime-coverage-v1.schema.json +86 -0
- data/schema/runtime-event-v1.schema.json +308 -0
- data/schema/table-simulation-v1.schema.json +70 -0
- data/sig/ibex/artifact_set.rbs +37 -0
- data/sig/ibex/cli/ambiguity.rbs +22 -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 +38 -0
- data/sig/ibex/cli/documentation.rbs +25 -0
- data/sig/ibex/cli/error_messages.rbs +57 -0
- data/sig/ibex/cli/explain.rbs +25 -0
- data/sig/ibex/cli/formatting.rbs +103 -0
- data/sig/ibex/cli/generation_artifacts.rbs +50 -0
- data/sig/ibex/cli/generation_error_messages.rbs +19 -0
- data/sig/ibex/cli/grammar_tests.rbs +36 -0
- data/sig/ibex/cli/ir_tools.rbs +51 -0
- data/sig/ibex/cli/lsp.rbs +14 -0
- data/sig/ibex/cli/outputs.rbs +17 -0
- data/sig/ibex/cli/racc_migration.rbs +30 -0
- data/sig/ibex/cli/samples.rbs +30 -0
- data/sig/ibex/cli/watch.rbs +43 -0
- data/sig/ibex/cli.rbs +104 -5
- 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 +85 -0
- data/sig/ibex/codegen/generated_action_abi.rbs +101 -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 +84 -4
- data/sig/ibex/codegen/report.rbs +8 -0
- data/sig/ibex/codegen/ruby.rbs +97 -23
- 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 +25 -0
- data/sig/ibex/codegen/ruby_table_metadata.rbs +26 -0
- data/sig/ibex/codegen/ruby_value_printers.rbs +28 -0
- data/sig/ibex/coverage/collector.rbs +76 -0
- data/sig/ibex/coverage/event_stream.rbs +42 -0
- data/sig/ibex/coverage/report.rbs +100 -0
- data/sig/ibex/coverage/runtime_event_validator.rbs +68 -0
- data/sig/ibex/coverage.rbs +7 -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/frontend/ast.rbs +208 -19
- data/sig/ibex/frontend/bootstrap_parser.rbs +11 -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 +135 -0
- data/sig/ibex/frontend/generated_parser.rbs +218 -68
- data/sig/ibex/frontend/generated_parser_base.rbs +61 -10
- 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 +54 -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/regenerator.rbs +11 -0
- data/sig/ibex/frontend/resolution.rbs +33 -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 +36 -3
- 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 +53 -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 +73 -5
- data/sig/ibex/frontend/token_adapter/rule_state.rbs +20 -0
- data/sig/ibex/frontend/token_adapter.rbs +5 -2
- data/sig/ibex/frontend.rbs +1 -1
- data/sig/ibex/generation_input.rbs +37 -0
- data/sig/ibex/generation_manifest.rbs +67 -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 +8 -2
- data/sig/ibex/ir/grammar_ir.rbs +75 -15
- data/sig/ibex/ir/lexer_ir.rbs +57 -0
- data/sig/ibex/ir/migration.rbs +34 -0
- data/sig/ibex/ir/serialize.rbs +23 -6
- data/sig/ibex/ir/validator/automaton.rbs +109 -0
- data/sig/ibex/ir/validator/base.rbs +65 -0
- data/sig/ibex/ir/validator/grammar.rbs +184 -0
- data/sig/ibex/ir/validator/lexer.rbs +37 -0
- data/sig/ibex/ir/validator.rbs +16 -0
- data/sig/ibex/ir.rbs +38 -4
- data/sig/ibex/lalr/build_metrics.rbs +20 -0
- data/sig/ibex/lalr/builder.rbs +95 -15
- data/sig/ibex/lalr/conflict_search.rbs +7 -3
- data/sig/ibex/lalr/counterexample.rbs +5 -2
- data/sig/ibex/lalr/direct_lookaheads.rbs +86 -0
- data/sig/ibex/lalr/ielr_partition.rbs +59 -0
- data/sig/ibex/lalr/on_error_reductions.rbs +22 -0
- data/sig/ibex/lalr.rbs +6 -0
- 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 +30 -0
- data/sig/ibex/lsp/position_codec.rbs +40 -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 +78 -0
- data/sig/ibex/lsp/symbol_index_builder.rbs +87 -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 +25 -0
- data/sig/ibex/lsp/transport.rbs +35 -0
- data/sig/ibex/lsp/workspace.rbs +41 -0
- data/sig/ibex/lsp/workspace_analyzer.rbs +69 -0
- data/sig/ibex/lsp.rbs +7 -0
- data/sig/ibex/normalize/declarations.rbs +31 -0
- data/sig/ibex/normalize/diagnostics.rbs +9 -0
- data/sig/ibex/normalize/expander.rbs +20 -14
- data/sig/ibex/normalize/expression.rbs +10 -10
- data/sig/ibex/normalize/inline_expansion.rbs +120 -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 +32 -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 +46 -0
- data/sig/ibex/normalize/recovery_declarations.rbs +24 -0
- data/sig/ibex/normalize.rbs +123 -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 +53 -0
- data/sig/ibex/racc_migration.rbs +8 -0
- data/sig/ibex/rake_task.rbs +51 -0
- data/sig/ibex/samples.rbs +51 -0
- data/sig/ibex/table_simulation/result.rbs +32 -0
- data/sig/ibex/table_simulation/simulator.rbs +98 -0
- data/sig/ibex/table_simulation/step.rbs +40 -0
- data/sig/ibex/table_simulation/text.rbs +14 -0
- data/sig/ibex/table_simulation.rbs +7 -0
- data/sig/ibex/tables.rbs +0 -26
- data/sig/ibex/watch/runner.rbs +48 -0
- data/sig/ibex/watch/source_snapshot.rbs +42 -0
- data/sig/ibex/watch.rbs +7 -0
- data/sig/ibex.rbs +2 -0
- metadata +301 -16
- 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/docs/architecture.md
CHANGED
|
@@ -3,26 +3,177 @@
|
|
|
3
3
|
Ibex keeps syntax, grammar meaning, automaton construction, and output concerns behind two versioned immutable contracts.
|
|
4
4
|
|
|
5
5
|
```text
|
|
6
|
-
.y
|
|
7
|
-
Ruby DSL
|
|
6
|
+
.y root/fragments -> Frontend Lexer/CST -> self-hosted LR Parser -> canonical Resolver ─┐
|
|
7
|
+
Ruby DSL ───────────────────────────────────────────────────────┴─> Grammar AST -> Normalizer -> Grammar IR
|
|
8
|
+
| |
|
|
9
|
+
| Lexer IR v1
|
|
8
10
|
|
|
|
9
11
|
set analysis
|
|
10
12
|
|
|
|
11
|
-
SLR/LALR/LR1 Builder -> Automaton IR
|
|
13
|
+
SLR/LALR/IELR/LR1 Builder -> Automaton IR
|
|
12
14
|
|
|
|
13
|
-
|
|
15
|
+
Ruby/RBS/action-shadow generators / report / DOT / Mermaid / HTML / counterexamples
|
|
14
16
|
```
|
|
15
17
|
|
|
16
18
|
Frontend changes stop at the Normalizer. Algorithm strategies consume Grammar IR and produce identical Automaton IR shapes.
|
|
17
19
|
Outputs consume Automaton IR and never call builder internals. The CLI only connects stages and supports JSON resumption.
|
|
18
20
|
|
|
21
|
+
An optional root-only `lexer` declaration normalizes to independently versioned
|
|
22
|
+
Lexer IR v1 and is embedded unchanged in Grammar IR v2. Its flat rule list
|
|
23
|
+
records state, declaration id, pattern source/options, action, and provenance;
|
|
24
|
+
`--emit=lexer-ir` exposes the same document. Code generation compiles every
|
|
25
|
+
pattern with an internal current-position anchor and emits immutable,
|
|
26
|
+
state-indexed rules. Per-parser mutable input, position, emission, and state
|
|
27
|
+
stacks live in `Runtime::GeneratedLexer`, never in the tables. See
|
|
28
|
+
[ADR 0014](decisions/0014-versioned-generated-lexer.md).
|
|
29
|
+
|
|
30
|
+
`pragma cst` remains an optional Grammar IR v2 flag. Regenerated format-v6
|
|
31
|
+
tables add deterministic kind and normalized slot metadata. `Runtime::Parser`
|
|
32
|
+
builds a pure-syntax Green entry for every shift and reduction on a stack
|
|
33
|
+
parallel to the semantic stack, so tree shape no longer depends on semantic
|
|
34
|
+
actions. Generated lexer skips become token-owned trivia. Parser failure,
|
|
35
|
+
repair, and lexer failure remain explicit and lossless. See
|
|
36
|
+
[ADR 0016](decisions/0016-red-green-concrete-syntax.md) and the
|
|
37
|
+
[CST guide](cst.md). Batch CST, typed views, editing, and serialization form
|
|
38
|
+
the Stable v1 contract. The runtime accepts structured CST metadata only in
|
|
39
|
+
the current format and rejects older CST tables before reading input; see
|
|
40
|
+
[ADR 0008](decisions/0008-versioned-runtime-package-boundary.md).
|
|
41
|
+
|
|
42
|
+
## Red/Green CST v2
|
|
43
|
+
|
|
44
|
+
Green nodes and tokens contain no parents, source objects, absolute positions,
|
|
45
|
+
semantic values, or parser states. Their integer kinds, binary text, trivia,
|
|
46
|
+
flags, widths, children, and descendant counts are immutable and
|
|
47
|
+
Ractor-shareable. A session-owned `NodeCache` interns unannotated values. Lazy
|
|
48
|
+
Red wrappers add occurrence-specific parent, index, offset, span, location, and
|
|
49
|
+
typed-field navigation. The root is `source_file(start, EOF)`, and
|
|
50
|
+
`to_source` is byte exact for the `leading` and `balanced` trivia policies.
|
|
51
|
+
|
|
52
|
+
Generated `Parser::Syntax::<Name>` classes are typed views over Red nodes using
|
|
53
|
+
the same normalized `@node` metadata as Data AST generation. Persistent edits
|
|
54
|
+
replace one Green occurrence and copy its ancestor path; rewriters, batched
|
|
55
|
+
editors, annotations, and identity-skipping text diffing share that mechanism.
|
|
56
|
+
See [ADR 0017](decisions/0017-persistent-syntax-artifacts.md).
|
|
57
|
+
|
|
58
|
+
`ibex_cst` schema v1 serializes the Green root, kind metadata, compatibility
|
|
59
|
+
counts, and optional preorder parser memo independently of Grammar IR.
|
|
60
|
+
Validation reconstructs every derived width, flag, and descendant count.
|
|
61
|
+
Non-UTF-8 bytes use canonical Base64. See
|
|
62
|
+
[ADR 0017](decisions/0017-persistent-syntax-artifacts.md).
|
|
63
|
+
|
|
64
|
+
Incremental sessions are syntax-only: parser production actions do not run.
|
|
65
|
+
The generated lexer first validates token/state resynchronization. `Blender`
|
|
66
|
+
then offers either a fresh token or an old Green nonterminal to the LR driver.
|
|
67
|
+
A subtree is pushed directly through `goto` only when damage, recorded
|
|
68
|
+
left-state, follow-token identity, error flags, and positive width satisfy the
|
|
69
|
+
conservative reuse proof. Token and parse memos remain preorder/occurrence
|
|
70
|
+
state owned by one session; resource exhaustion falls back to the fresh token
|
|
71
|
+
stream. See [ADR 0018](decisions/0018-conservative-incremental-syntax-reuse.md).
|
|
72
|
+
|
|
73
|
+
Alternative-level `@node` declarations are preserved as Grammar IR v2
|
|
74
|
+
production metadata. Runtime Ruby, static action-shadow Ruby, and generated
|
|
75
|
+
RBS all derive Data node classes and Visitor/Listener hooks from that same
|
|
76
|
+
metadata; action source is never inspected to infer a shape. Symbol semantic
|
|
77
|
+
types and fully annotated nonterminals supply field types.
|
|
78
|
+
|
|
19
79
|
The text frontend's canonical syntax is `lib/ibex/frontend/grammar.y`. Ibex generates and commits
|
|
20
80
|
`lib/ibex/frontend/generated_parser.rb`; the public `Frontend::Parser` always delegates to that class. Lexer `Token` objects remain
|
|
21
81
|
the semantic values passed through `TokenAdapter`, preserving their `Location` in AST nodes and diagnostics. The explicitly named
|
|
22
82
|
handwritten `BootstrapParser` is excluded from normal loading and exists only to break the regeneration cycle. See
|
|
23
|
-
[ADR
|
|
83
|
+
[ADR 0003](decisions/0003-self-hosted-grammar-frontend.md) for the update procedure and boundary.
|
|
84
|
+
`lib/ibex/frontend/shadow_grammar.y` describes the same frontend with parameterized list rules and an inline terminal wrapper.
|
|
85
|
+
It is generated only in tests and must match the production parser's AST across the canonical grammar and extended fixtures;
|
|
86
|
+
see the [development guide](development.md).
|
|
87
|
+
|
|
88
|
+
The lexer also retains an immutable lexical CST without changing the semantic token stream. `Frontend::Parser#parse_document`
|
|
89
|
+
returns a `SourceDocument` whose source, token-indexed segments, and AST come from that single lexer/parser pass.
|
|
90
|
+
`SourceSpan` uses half-open zero-based byte offsets and one-based Unicode-scalar line/column positions. Actions and user-code
|
|
91
|
+
bodies remain opaque segments; whitespace, line breaks, both comment forms, user-code markers, and EOF remain individually traversable.
|
|
92
|
+
`render`, byte slicing, and byte/line/column conversion provide the common source contract for formatter, documentation, include,
|
|
93
|
+
and language-server layers. `RuleDocumentation` correlates immediately preceding `##` comment-only lines with semantic rule
|
|
94
|
+
locations and copy-enriches generated Root/Fragment nodes; occupied opaque-segment lines are never scanned as comments. See
|
|
95
|
+
[ADR 0004](decisions/0004-shared-semantic-and-lossless-source-model.md).
|
|
96
|
+
|
|
97
|
+
`Frontend::Formatter` classifies the document's existing semantic tokens, replaces only whitespace/newline trivia, and protects
|
|
98
|
+
token, comment, action, heredoc, marker, and user-code bytes. It reparses the rendered root or fragment in the same frontend mode
|
|
99
|
+
and compares ASTs with an explicit work stack after removing location fields. The CLI's stdout, batch check, and transactional
|
|
100
|
+
in-place surfaces are therefore downstream consumers of `SourceDocument`, not an alternate grammar parser. Existing newline
|
|
101
|
+
segment spellings and blank-line counts survive required line boundaries; new boundaries use the first newline even when it is
|
|
102
|
+
inside opaque text. Batch stages and hard-link backups live beside each resolved target. Alias rejection, reverse rollback, and
|
|
103
|
+
all-directory synchronization preserve full file modes and relative or absolute symlink identities. Backups are synchronized
|
|
104
|
+
before installation; a failed restore preserves its backup, while post-commit cleanup problems are status-0 warnings. See
|
|
105
|
+
[ADR 0004](decisions/0004-shared-semantic-and-lossless-source-model.md).
|
|
24
106
|
|
|
25
|
-
|
|
107
|
+
`Frontend::SourceLoader` is the shared disk/overlay read boundary. Resolver's default loader retains canonical filesystem
|
|
108
|
+
behavior; LSP injects open buffers, including safe new files, while the resolver continues to enforce realpath containment,
|
|
109
|
+
symlink escape rejection, cycle identity, and diamond deduplication. `LSP::DocumentStore` layers monotonic open versions,
|
|
110
|
+
root/include closures, reverse dependencies, and disk restoration over that loader. `PositionCodec` is the only UTF-16 adapter
|
|
111
|
+
over frontend byte/scalar spans. `SymbolIndex` derives navigation and guarded rename edits from parsed nodes and lossless tokens,
|
|
112
|
+
never from opaque Ruby or textual scanning. Content-Length transport, lifecycle handling, and request handlers remain separate
|
|
113
|
+
from workspace semantics; see [ADR 0004](decisions/0004-shared-semantic-and-lossless-source-model.md).
|
|
114
|
+
|
|
115
|
+
CLI file generation renders every requested output into an immutable `ArtifactSet` before entering `GenerationTransaction`.
|
|
116
|
+
The transaction records the exact root, fragment, IR, and message bytes read through `GenerationInput`, rejects portable target
|
|
117
|
+
collisions and input aliases, takes stable sidecar locks, stages and synchronizes every file, and can restore hard-link backups
|
|
118
|
+
in reverse publication order. Ordinary companions publish first, the parser second, and an opt-in generation manifest last.
|
|
119
|
+
That manifest is the coherence marker: readers verify its listed paths, sizes, and SHA-256 digests and retry from a newly read
|
|
120
|
+
manifest on a mismatch. It is not a claim that several filesystem renames occur atomically. `--watch` feeds the same transaction
|
|
121
|
+
only candidates whose complete canonical source closure and failed include attempts remain unchanged across rendering and
|
|
122
|
+
publication. Portable polling, bounded debounce, failure deduplication, and cancellable nonblocking locks keep the last successful
|
|
123
|
+
generation usable while a source is invalid; see [ADR 0013](decisions/0013-transactional-generation-publication.md).
|
|
124
|
+
The executable's ordinary generation path declares this pipeline directly instead of loading the complete library and every
|
|
125
|
+
subcommand. Optional subcommands and generation outputs load at their invocation boundary while their public constants remain
|
|
126
|
+
autoloadable.
|
|
127
|
+
|
|
128
|
+
Extended grammar paths cross an explicit `Frontend::Resolver` boundary. The canonical `import` declaration and compatible
|
|
129
|
+
`include` spelling share this boundary. Roots retain class, start, options, and user code;
|
|
130
|
+
fragments contain composable declarations and rules. Canonical realpaths define DFS order, diamond deduplication, cycle identity,
|
|
131
|
+
and the Rake dependency closure. Canonical dirname ancestry keeps every resolved target below the root grammar directory after
|
|
132
|
+
symlink resolution, including when that directory is a filesystem or drive root. The source-only Parser never follows an
|
|
133
|
+
include. A `Resolution` recursively freezes its owned AST and defensive provenance copies while retaining rule identity for
|
|
134
|
+
include-chain lookup. Rake resolves this closure at task definition and refuses invalid graphs before timestamp checks can reuse
|
|
135
|
+
a stale output; see [ADR 0005](decisions/0005-contained-grammar-composition.md).
|
|
136
|
+
|
|
137
|
+
Extended parameterized definitions remain structural AST templates rather than grammar symbols. The Normalizer validates the
|
|
138
|
+
complete template graph, interns an impossible `$parameter_N` helper for each canonical call, records that helper in a memo
|
|
139
|
+
before expanding its body, and substitutes formals through nested EBNF and calls. Resumable alternative, item, and EBNF
|
|
140
|
+
continuations on an explicit depth-first worklist preserve ordinary lowering order and active-depth semantics without consuming
|
|
141
|
+
the Ruby call stack. Same-argument recursion therefore closes over the memo, while a configurable total-specialization budget
|
|
142
|
+
and structural constructor-growth detection bound argument-growing recursion without an arbitrary depth cutoff. Template actions,
|
|
143
|
+
precedence, metadata, documentation, locations, and definition include chains flow into the specialized productions; see
|
|
144
|
+
[ADR 0006](decisions/0006-bounded-structural-grammar-lowering.md).
|
|
145
|
+
|
|
146
|
+
Inline definitions are lowered temporarily, then a bounded deterministic post-pass substitutes marked alternatives through
|
|
147
|
+
ordinary, parameterized, and EBNF productions before diagnostics and LR construction. It removes every marked symbol and
|
|
148
|
+
production, remaps the dense symbol/production ids, and retains eliminated semantic reductions as a versioned post-order
|
|
149
|
+
action plan. The plan addresses flattened physical values followed by earlier logical results, records a nullable semantic
|
|
150
|
+
`result_type` on every newly emitted step, reconstructs surrounding stack
|
|
151
|
+
prefixes and semantic spans, and remains executable after IR serialization. Cycle validation covers paths through ordinary
|
|
152
|
+
rules and templates; the default 10,000-production cartesian budget is configurable. See
|
|
153
|
+
[ADR 0006](decisions/0006-bounded-structural-grammar-lowering.md).
|
|
154
|
+
|
|
155
|
+
The strict generated frontend remains the grammar authority during batch diagnostics. A diagnostic parse retries it after
|
|
156
|
+
suppressing only a whole declaration, whole rule, or outer alternative at balanced delimiters. Each retry must remove a new
|
|
157
|
+
original token and both attempts and emitted diagnostics are bounded. Lexical and syntax phases collect independently before a
|
|
158
|
+
global source-order limit is applied, so an earlier syntax error cannot be hidden by a later lexical error. Machine-readable
|
|
159
|
+
diagnostics retain source spans, defensive locations, and stable codes. A repaired AST is marked partial by `ParseResult`, and
|
|
160
|
+
is not attached to the unchanged source document. After a successful root parse, the CLI reports the first resolver grammar
|
|
161
|
+
failure through the same diagnostic schema, while actual resolution I/O failures remain invocation errors. The CLI exposes this
|
|
162
|
+
analysis only through `ibex diagnose`; see [ADR 0004](decisions/0004-shared-semantic-and-lossless-source-model.md).
|
|
163
|
+
|
|
164
|
+
The RBS generator emits the generated class namespace, superclass, parser-table constants, `.parser_tables` contract, and
|
|
165
|
+
private reduction and composed-fragment signatures. Declared symbol types refine the RHS tuple and LHS result independently,
|
|
166
|
+
with `untyped` used at undeclared boundaries; composed inputs resolve either a physical symbol type or an earlier plan step's
|
|
167
|
+
`result_type`. Reduction methods also receive a location tuple, surrounding location stack, and optional
|
|
168
|
+
`Runtime::LocationSpan`. Generated tables mark whether actions require locations. The runtime leaves the location stack
|
|
169
|
+
unallocated for ordinary two-element-token parses and creates or backfills it only when an action, tooling observer, or
|
|
170
|
+
three-element token requires it. The public immutable `Ibex::Location` range and `loc`/`result_loc` action helpers sit above the
|
|
171
|
+
same stack contract.
|
|
172
|
+
Default source mapping compiles opaque action methods with `class_eval` when the generated class loads. The opt-in action-shadow
|
|
173
|
+
generator makes those exact method bodies visible to Steep without runtime loading: runtime and shadow output share one method
|
|
174
|
+
source builder, while the shadow omits parser infrastructure and every user-code section. Ibex only generates this source;
|
|
175
|
+
executing Steep remains an application/CI boundary. See
|
|
176
|
+
[ADR 0011](decisions/0011-versioned-semantic-action-boundary.md). The
|
|
26
177
|
gem also ships a one-to-one rbs-inline-generated signature tree under `sig/` for every Ruby source in `lib/`, including the
|
|
27
178
|
self-hosted parser. CI regenerates into an empty temporary directory, compares the complete trees, validates the RBS environment,
|
|
28
179
|
and runs Steep against the entire library. Token/location records, grammar AST nodes, parser classifier and bootstrap state, the
|
|
@@ -30,7 +181,7 @@ Ruby DSL, IR records, and automaton actions use concrete domain types. Generated
|
|
|
30
181
|
cells, decoded JSON values, and user methods embedded as opaque Ruby source remain `untyped`; applications can reopen the generated
|
|
31
182
|
class in their own RBS files to declare embedded methods.
|
|
32
183
|
|
|
33
|
-
## Grammar IR
|
|
184
|
+
## Grammar IR versions 1 and 2
|
|
34
185
|
|
|
35
186
|
Top-level fields:
|
|
36
187
|
|
|
@@ -38,30 +189,67 @@ Top-level fields:
|
|
|
38
189
|
|---|---|
|
|
39
190
|
| `ibex_ir`, `schema_version` | `"grammar"`, `1` |
|
|
40
191
|
| `class_name`, `superclass` | Generated Ruby class contract |
|
|
41
|
-
| `start`, `expect`, `options` |
|
|
192
|
+
| `start`, optional `starts`, `expect`, `options` | Primary/ordered start names, unresolved S/R expectation, result/action flags |
|
|
193
|
+
| optional `params`, `printers` | Generated-constructor keywords and symbol-specific debug value formatters |
|
|
194
|
+
| optional `lexer` | Embedded independently versioned Lexer IR v1 |
|
|
42
195
|
| `symbols` | Interned terminals and nonterminals; `$eof` id 0 and `error` id 1 |
|
|
43
196
|
| `productions` | Numeric LHS/RHS ids, action, precedence override, source origin |
|
|
44
197
|
| `user_code`, `conversions`, `warnings` | Concatenated code, external token expressions, structured diagnostics |
|
|
45
198
|
| `user_code_chunks` | Optional opaque chunks with first-code-line locations for compatible source mapping |
|
|
46
199
|
|
|
47
|
-
Warning records use
|
|
48
|
-
`duplicate_production`, and `empty_language
|
|
200
|
+
Warning records use the additive type vocabulary `undeclared_terminal`, `unused_terminal`, `unused_precedence`,
|
|
201
|
+
`unreachable_terminal`, `unreachable_nonterminal`, `duplicate_production`, and `empty_language`, and retain source locations.
|
|
202
|
+
Schema-v1 readers must ignore warning types they do not recognize. The CLI applies display/error policy at the boundary;
|
|
49
203
|
normalization and IR serialization do not discard diagnostics.
|
|
50
204
|
|
|
51
|
-
A symbol has `id`, `name`, `kind`, `reserved`, optional `prec {associativity, level}`,
|
|
52
|
-
`
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
205
|
+
A symbol has `id`, `name`, `kind`, `reserved`, optional `prec {associativity, level}`, `loc`, `display_name`, and
|
|
206
|
+
`semantic_type`. The last two fields are omitted when undeclared, so older schema-v1 documents remain byte-stable and loadable.
|
|
207
|
+
A production has `id`, `lhs`, `rhs`, optional `action`, optional `prec_override`, and `origin`. Synthetic EBNF origins include
|
|
208
|
+
an additive, deterministic `expression` label used by text, DOT, and HTML presentation while numeric symbol identities remain
|
|
209
|
+
unchanged. An action has opaque `code`, `loc`, `named_refs [{name,index}]`, and `context_length`; middle-action helpers use the
|
|
210
|
+
last field to view preceding stack values.
|
|
211
|
+
|
|
212
|
+
IR objects and nested collections are frozen. JSON keys have deterministic order, so dump/load/dump is byte-stable. The additive
|
|
213
|
+
`user_code_chunks` field remains optional in version 1 so older JSON stays loadable.
|
|
214
|
+
|
|
215
|
+
New normalized grammars use version 2. It keeps every version-1 semantic field and adds explicit nullable metadata:
|
|
216
|
+
|
|
217
|
+
| Record | Version-2 metadata |
|
|
218
|
+
|---|---|
|
|
219
|
+
| grammar | `source_provenance {file, root, byte_span {start,end}}` and optional `migration` loss record |
|
|
220
|
+
| symbol | `doc` |
|
|
221
|
+
| production | `doc` and `expansion {parameter, inline, include_chain}` |
|
|
222
|
+
| action | `composition {strategy, fragments, plan {version, physical, steps}}`; new steps include nullable `result_type` |
|
|
223
|
+
|
|
224
|
+
The source-only text frontend supplies the source filename and leaves unknown metadata null. A resolved grammar also supplies its
|
|
225
|
+
canonical source root and each production's include chain while preserving its original-file origin. Lossless rule comments
|
|
226
|
+
populate symbol and user-production documentation, including through fragment resolution; synthetic EBNF helpers remain
|
|
227
|
+
undocumented. Parameterized specializations populate `expansion.parameter` with the template name and canonical structural
|
|
228
|
+
arguments while retaining the definition's include chain. Version-1 upgrades mark every unrecoverable metadata family in
|
|
229
|
+
`migration.unavailable` instead of guessing.
|
|
230
|
+
For compatibility with earlier version-2 documents, the input schema also accepts an absent composition-step
|
|
231
|
+
`result_type`; generators treat it as `untyped`.
|
|
232
|
+
`Serialize.load` and `Validator.validate` accept both versions; a loaded version-1 object dumps with the original version-1
|
|
233
|
+
shape. `IR::Migration.to_version` upgrades version 1 to 2 and is idempotent at version 2. The CLI exposes this as
|
|
234
|
+
`ibex migrate-ir INPUT --to=2 [-o FILE]`; file output uses an atomic same-directory rename and refuses to alias the input.
|
|
235
|
+
|
|
236
|
+
The v1 stabilization freeze covers required core fields, meanings, ordering,
|
|
237
|
+
identity, and validation behavior. The future `x-` experimental namespace is
|
|
238
|
+
outside that freeze, but current schemas remain closed and reject unknown
|
|
239
|
+
fields. Experimental data must therefore begin in a new additive schema
|
|
240
|
+
version rather than weakening an existing document. See
|
|
241
|
+
[stability and deprecation](stability.md).
|
|
56
242
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
243
|
+
`Codegen::Documentation` renders normalized user rules and alternatives as escaped Markdown, self-contained accessible HTML, or
|
|
244
|
+
railroad SVG. The railroad renderer includes visible wrapped rule descriptions in its section-height calculation and exposes the
|
|
245
|
+
full escaped text through SVG descriptions. `ibex doc` resolves the same canonical include graph and writes to stdout or an
|
|
246
|
+
atomic file without generating or executing application parser code.
|
|
60
247
|
|
|
61
|
-
## Automaton IR
|
|
248
|
+
## Automaton IR versions 1 and 2
|
|
62
249
|
|
|
63
|
-
Top-level fields are `ibex_ir: "automaton"`, `schema_version`, `algorithm`, `grammar_digest`, embedded `grammar`, `states`,
|
|
64
|
-
`conflict_summary`. Embedding Grammar IR makes automaton JSON sufficient for code generation after
|
|
250
|
+
Top-level fields are `ibex_ir: "automaton"`, `schema_version`, `algorithm`, `grammar_digest`, embedded `grammar`, `states`,
|
|
251
|
+
optional `entry_states`, and `conflict_summary`. Embedding Grammar IR makes automaton JSON sufficient for code generation after
|
|
252
|
+
`--from=automaton-ir`. A multi-entry automaton maps every ordered grammar start name to its initial state.
|
|
65
253
|
|
|
66
254
|
Each state contains:
|
|
67
255
|
|
|
@@ -70,30 +258,136 @@ Each state contains:
|
|
|
70
258
|
- resolved terminal `actions` and nonterminal `gotos`;
|
|
71
259
|
- an optional reduce `default_action`, selected only when explicit error masks preserve every terminal lookup and reduce the
|
|
72
260
|
total encoded ACTION entries;
|
|
73
|
-
- every conflict, including precedence-resolved conflicts and the resolution reason
|
|
261
|
+
- every conflict, including precedence-resolved conflicts and the resolution reason; multi-entry conflicts also carry their
|
|
262
|
+
reachable `entries` and optional `composite` marker.
|
|
74
263
|
|
|
75
264
|
`conflict_summary.sr` counts unresolved default-shift conflicts for `expect`; `resolved_sr` counts retained precedence or
|
|
76
265
|
associativity decisions; `rr` counts reduce/reduce cells.
|
|
77
266
|
|
|
267
|
+
New automata use version 2 and always embed Grammar IR version 2. Migration recalculates `grammar_digest` from the upgraded
|
|
268
|
+
canonical grammar. Version-1 automata remain loadable, validatable, and byte-stable. Published Draft 2020-12 contracts for both
|
|
269
|
+
versions live under `schema/`; see
|
|
270
|
+
[ADR 0001](decisions/0001-versioned-ir-pipeline.md).
|
|
271
|
+
|
|
272
|
+
`--emit=sets` is a deterministic analysis view rather than another IR: it emits lexically sorted nullable nonterminals and
|
|
273
|
+
FIRST/FOLLOW maps for nonterminals. DOT, Mermaid, and the self-contained searchable HTML report are deterministic presentation
|
|
274
|
+
views over Automaton IR.
|
|
275
|
+
|
|
276
|
+
## Construction algorithms and counterexamples
|
|
277
|
+
|
|
278
|
+
The `lalr` and `slr` strategies construct LR(0) states directly for a single entry. LALR lookaheads are the least fixed point of deterministic
|
|
279
|
+
shift, spontaneous-FIRST, and nullable-suffix propagation edges over item occurrences; SLR replaces completed lookaheads with
|
|
280
|
+
FOLLOW sets. Multiple entries seed distinct augmented canonical items and use canonical core merging because the direct
|
|
281
|
+
lookahead graph has a single-root contract. Canonical `lr1` retains the canonical collection. An explicit canonical-and-merge
|
|
282
|
+
LALR reference strategy proves byte equivalence without changing the Automaton IR algorithm label. `ielr` conservatively merges action-compatible canonical
|
|
283
|
+
states and refines partitions until outgoing transitions are congruent, avoiding LALR inadequacies without promising a minimum
|
|
284
|
+
state count. `--entry-isolation` instead constructs each start independently and concatenates the resulting state sets with
|
|
285
|
+
deterministic offsets. Shared builds attribute reachable entries to conflicts and compare isolated conflict fingerprints to
|
|
286
|
+
identify merge-created composite conflicts. All strategies use the same conflict resolver and default reduction pass. After a build, frozen diagnostic
|
|
287
|
+
`metrics` record the strategy and construction/final state counts, plus a canonical count only when one was actually built. See
|
|
288
|
+
[ADR 0007](decisions/0007-shared-parser-construction-pipeline.md).
|
|
289
|
+
|
|
290
|
+
`Ibex::LALR::Counterexample` consumes only Automaton IR. For each conflict it explores parser-stack configurations, forces the
|
|
291
|
+
competing actions, and searches for a common accepting suffix. A successful result contains both complete derivation trees and is
|
|
292
|
+
marked `unifying: true`. Search defaults to 32 tokens and 50,000 configurations; the Ruby and CLI APIs can set both positive
|
|
293
|
+
budgets. If no common sentence is found within them, the result is explicitly marked nonunifying and contains the deterministic
|
|
294
|
+
shortest reachability witness instead of claiming ambiguity.
|
|
295
|
+
|
|
296
|
+
`Ibex::Codegen::Explain` filters those immutable conflicts by state and canonical token identity before asking
|
|
297
|
+
`Counterexample#for_conflict` to search only the selected entries, then renders text or the versioned `explain` JSON analysis
|
|
298
|
+
shape. `Counterexample#all` retains its original all-conflict behavior. The view performs no additional parser analysis and does
|
|
299
|
+
not extend Grammar or Automaton IR.
|
|
300
|
+
|
|
301
|
+
The repository's self-authored representative grammar feeds the current versioned `ibex_benchmark` v2 document. Its JSON Schema
|
|
302
|
+
is shipped beside the IR schemas, while committed environment-specific observations live under the matching
|
|
303
|
+
`benchmark/results/vN` directory. Timing and peak RSS remain non-gating; CI reproduces only deterministic structure and digests.
|
|
304
|
+
See the [benchmark guide](../benchmark/README.md).
|
|
305
|
+
|
|
78
306
|
## Runtime table contract
|
|
79
307
|
|
|
80
308
|
Generated subclasses expose `.parser_tables` with a required `format_version`, external `tokens`, display `token_names`, ACTION
|
|
81
309
|
and GOTO tables, per-state default actions, and production `{lhs,length,action}` records. The runtime validates the version before
|
|
82
|
-
reading input and rejects missing or unsupported formats with a regeneration instruction
|
|
83
|
-
|
|
310
|
+
reading input and rejects missing or unsupported formats with a regeneration instruction. The generator emits v6. For non-CST
|
|
311
|
+
tables, the runtime accepts v1's two-argument actions, v2/v3 explicitly marked five-argument location actions, v3 explicitly
|
|
312
|
+
marked six-argument composed actions, v4 one-Array values actions, and v5/v6 positional actions. Marker contracts are validated
|
|
313
|
+
before input. A CST table is executable only when it uses current format-v6 structured metadata; older or boolean CST shapes
|
|
314
|
+
must be regenerated. See
|
|
315
|
+
[ADR 0008](decisions/0008-versioned-runtime-package-boundary.md). Plain tables are arrays of Hash rows. Compact tables use row
|
|
84
316
|
displacement with offsets, values, and row-ownership checks; both expose equivalent lookups. Default reductions are restricted
|
|
85
317
|
to known token ids, and explicit error masks preserve the pre-optimization result of every declared terminal cell, including
|
|
86
|
-
the synthetic `error` terminal.
|
|
87
|
-
|
|
318
|
+
the synthetic `error` terminal. Extended parser tables opt `expected_tokens` into lookahead correction: the runtime copies only
|
|
319
|
+
the state stack and simulates reductions and gotos for each declared terminal, without evaluating semantic actions. The explicit
|
|
320
|
+
`expected_tokens_exact` API exposes the same result for compatible tables. The deterministic size policy is fixed by
|
|
321
|
+
[ADR 0008](decisions/0008-versioned-runtime-package-boundary.md).
|
|
322
|
+
|
|
323
|
+
Runtime execution is packaged independently as `ibex-runtime`, with its own version and RBS tree. The generator package depends
|
|
324
|
+
on a compatible runtime series but does not duplicate runtime-owned files. Compact lookup values live in a runtime-safe leaf
|
|
325
|
+
file, while table construction remains generator-only. Normal output requires only `ibex/runtime`; `-E` embeds the same sources.
|
|
326
|
+
See [ADR 0008](decisions/0008-versioned-runtime-package-boundary.md).
|
|
88
327
|
|
|
89
328
|
The runtime maintains state and value stacks, pulls a lookahead only when required, and applies tagged `shift`, `reduce`,
|
|
90
329
|
`accept`, and `error` actions. Recovery pops to a state that shifts token id 1, suppresses repeated reports for three successful
|
|
91
|
-
shifts, and honors `yyerrok`. No-op
|
|
330
|
+
shifts, and honors `yyerrok`. No-op shift, reduce, recovery, location-aware, and discard extension points observe successfully
|
|
92
331
|
committed events without changing parser results; the recovery hook retains the pre-pop error context and is distinct from an
|
|
93
|
-
ordinary token shift. Their ordering and payload contract is
|
|
332
|
+
ordinary token shift. A configured value printer affects only human `yydebug` output. Their ordering and payload contract is
|
|
333
|
+
extended additively by
|
|
334
|
+
[ADR 0010](decisions/0010-committed-runtime-observation.md). Grammar-declared
|
|
335
|
+
symbol printers are optional IR v2 metadata compiled into private methods and
|
|
336
|
+
an id-indexed table.
|
|
337
|
+
|
|
338
|
+
Ordinary generated tables are recursively frozen and made Ractor-shareable. Threads and Ractors share those tables but parse
|
|
339
|
+
through distinct instances; stacks, lookahead, lexer state, callbacks, observers, and semantic values are session-owned. A
|
|
340
|
+
single instance rejects overlapping drivers. Immutable `Runtime::ResourceLimits` values bound every stack push and recovery
|
|
341
|
+
entry with finite defaults. Exhaustion raises the structured `ResourceLimitError`; see
|
|
342
|
+
[ADR 0009](decisions/0009-isolated-parser-sessions.md).
|
|
343
|
+
|
|
344
|
+
Extended Grammar IR v2 may additionally carry synchronization terminals and ordered `%on_error_reduce` groups. Table
|
|
345
|
+
construction fills only otherwise erroneous ACTION cells with a unique highest-priority completed declared production. At
|
|
346
|
+
runtime, an explicit shift of the synthetic `error` token always wins; only when it is unavailable does panic recovery discard
|
|
347
|
+
through a configured synchronization token and pop to a state that accepts that retained lookahead. Generated parsers without
|
|
348
|
+
sync declarations omit the optional table field. The pull/push ordering and observer contract are fixed by
|
|
349
|
+
the runtime and grammar reference documentation.
|
|
350
|
+
|
|
351
|
+
The separate `Runtime::Parser#observe` API publishes ordered, immutable schema-v1 events for tooling. Its bounded sanitizer
|
|
352
|
+
copies only JSON data and never retains application identities or private stacks. With no observer, parse transitions construct
|
|
353
|
+
no Event, payload summary, or dispatch snapshot; parser initialization still creates its ownership mutex. Generated tables
|
|
354
|
+
contribute grammar digest, table format, state count, and production count to the `start` event. `Runtime::EventJSONLTracer`
|
|
355
|
+
exposes the versioned stream; the original hook-based `Runtime::JSONLTracer` remains byte-compatible. The protocol and
|
|
356
|
+
exception/threading behavior are fixed by
|
|
357
|
+
[ADR 0010](decisions/0010-committed-runtime-observation.md).
|
|
358
|
+
|
|
359
|
+
Optional `Runtime::RepairPolicy` drives a bounded Dijkstra search over copied state stacks and buffered token identities. Search
|
|
360
|
+
uses explicit/default ACTION, GOTO, and production shape only; it never executes semantic code. A selected immutable edit plan is
|
|
361
|
+
reported once, then replayed through the ordinary runtime so actions and hooks remain committed-path effects. Pull lookahead,
|
|
362
|
+
push buffering, deterministic tie-breaking, fallback to yacc recovery, and no-policy compatibility are fixed by
|
|
363
|
+
[ADR 0012](decisions/0012-bounded-nonexecuting-analysis.md).
|
|
364
|
+
|
|
365
|
+
`Coverage::Collector` accepts only contiguous, complete runtime-event sessions with generated parser metadata. It counts entries
|
|
366
|
+
to the initial, shift, reduce-goto, and recovery states and counts committed reductions by production id. `Coverage::Report`
|
|
367
|
+
publishes ascending sparse hit arrays under the versioned runtime-coverage schema. Merge requires identical full grammar digest,
|
|
368
|
+
table format, and totals and uses checked addition. The coverage CLI only reads bounded JSON/JSON Lines and never loads generated
|
|
369
|
+
Ruby or executes semantic actions; collection, merge, threshold, and atomic-output policy are fixed by
|
|
370
|
+
[ADR 0010](decisions/0010-committed-runtime-observation.md).
|
|
371
|
+
|
|
372
|
+
`TableSimulation::Simulator` is a separate state-stack interpreter over validated Automaton IR. It resolves an explicit ACTION
|
|
373
|
+
cell before a default action, so explicit error masks remain authoritative, and never evaluates the opaque semantic-action
|
|
374
|
+
source stored in Grammar IR. Immutable steps expose state, lookahead, selected action source, reduction/goto metadata, and stack
|
|
375
|
+
depth. Action and stack budgets bound default/epsilon cycles and growth. The text/JSON CLI and versioned output contract are
|
|
376
|
+
fixed by [ADR 0012](decisions/0012-bounded-nonexecuting-analysis.md).
|
|
377
|
+
|
|
378
|
+
Grammar IR v2 may carry ordered accept/reject source tests without adding them to parser tables. `GrammarTests::Runner` generates
|
|
379
|
+
one embedded parser and executes fresh parser instances in a separate Ruby process, distinguishing `ParseError` rejection from
|
|
380
|
+
lexer/application errors and bounding the whole suite by a timeout. The separate runner loads the generated file, so guarded
|
|
381
|
+
footer programs stay inactive. The source contract, isolation boundary, and CI behavior are fixed by
|
|
382
|
+
the grammar reference documentation.
|
|
94
383
|
|
|
95
384
|
## Clean-room boundary
|
|
96
385
|
|
|
97
386
|
Implementation work uses public racc documentation, CLI black-box behavior, and published LR algorithms only. racc implementation
|
|
98
387
|
sources and generated source are not inputs to the design. Self-authored compatibility grammars execute both outputs in separate
|
|
99
388
|
processes and compare observable results.
|
|
389
|
+
|
|
390
|
+
`RaccMigration::Checker` treats grammar code as opaque while reporting default-mode parse/normalization errors and known runtime
|
|
391
|
+
coupling. The separate harness generator emits source only; its output refuses an empty corpus and makes bounded child-process
|
|
392
|
+
execution explicit. The boundary is fixed by
|
|
393
|
+
[ADR 0012](decisions/0012-bounded-nonexecuting-analysis.md).
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# CST Red/Green migration
|
|
2
|
+
|
|
3
|
+
The runtime supports only the current format-v6 Red/Green representation for
|
|
4
|
+
`pragma cst`. CST parser tables from formats v1 through v5, and boolean
|
|
5
|
+
`cst: true` tables without structured metadata, fail before the first token is
|
|
6
|
+
read and instruct the application to regenerate. Older non-CST parser tables
|
|
7
|
+
remain executable.
|
|
8
|
+
|
|
9
|
+
Regenerate with the same command used for the grammar, for example:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
ibex grammar.y -o parser.rb
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Upgrade the generator and runtime together, regenerate the parser, and update
|
|
16
|
+
consumers to the current APIs below. The removed `CST::Trivia`, `CST::Token`,
|
|
17
|
+
`CST::Missing`, `CST::Error`, and `CST::Node` constants are not defined.
|
|
18
|
+
|
|
19
|
+
## Parsing
|
|
20
|
+
|
|
21
|
+
Use `parse_with_syntax` when both the semantic result and syntax are needed:
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
result = parser.parse_with_syntax(source, file: "input.txt")
|
|
25
|
+
value = result.value
|
|
26
|
+
root = result.syntax_root
|
|
27
|
+
diagnostics = result.diagnostics
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`parse`, `do_parse`, and `yyparse` keep returning the semantic result. After a
|
|
31
|
+
CST parse, `syntax_root` exposes the most recently built Red root.
|
|
32
|
+
|
|
33
|
+
## Changed tree shape
|
|
34
|
+
|
|
35
|
+
The new root is always `source_file`:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
source_file
|
|
39
|
+
├── selected start-symbol node
|
|
40
|
+
└── $eof
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The EOF token owns final trivia. Code that previously treated the returned CST
|
|
44
|
+
as the start node should use `result.syntax_root.children.fetch(0)`.
|
|
45
|
+
|
|
46
|
+
The legacy implementation exposed semantic values inside an actionless
|
|
47
|
+
parent. For example, an action-bearing `term` could appear as a `CST::Token`
|
|
48
|
+
whose symbol was `"term"` and whose value was the action result. Format v6
|
|
49
|
+
always exposes the physical `term` syntax node in that position. Read the
|
|
50
|
+
semantic result from `result.value`; syntax children never contain semantic
|
|
51
|
+
values.
|
|
52
|
+
|
|
53
|
+
These are the primary incompatible shapes found by the migration
|
|
54
|
+
characterization suite. `deconstruct` continues to return syntax children and
|
|
55
|
+
`deconstruct_keys` retains the compatibility keys. Typed field keys are added
|
|
56
|
+
from `@node` slot metadata.
|
|
57
|
+
|
|
58
|
+
## Removed public API mapping
|
|
59
|
+
|
|
60
|
+
The inventory below records the removed values and their format-v6
|
|
61
|
+
replacements.
|
|
62
|
+
|
|
63
|
+
| Removed value and members | Previous use | Format-v6 replacement |
|
|
64
|
+
| --- | --- | --- |
|
|
65
|
+
| `CST::Trivia#text`, `#location`, `#to_h` | leading/trailing trivia assertions | `GreenTrivia#text` and `#kind`; obtain absolute location from the owning Red token |
|
|
66
|
+
| `CST::Token#symbol`, `#value`, `#location`, `#leading_trivia` | terminal names, lexer action values, positions, skipped text | `SyntaxToken#kind_name`/`#symbol`, `#location`, and `#leading_trivia`; compatibility `#value` returns the same source bytes as `#text`, while semantic lexer values stay in the normal action/value path |
|
|
67
|
+
| `CST::Token#kind`, `#children`, `#deconstruct`, `#deconstruct_keys`, `#to_h` | error classification and pattern matching | integer `#kind`, `#error?`/`#missing?`, empty `#children`/`#deconstruct`, and compatibility pattern/hash keys |
|
|
68
|
+
| `CST::Missing` | bounded-repair insertion checks | `SyntaxToken#missing?`, `GreenToken#expected_kind`, and `CONTAINS_MISSING` |
|
|
69
|
+
| `CST::Error#reason` | lexical, syntax, delete, and discard checks | `SyntaxToken#error?`, `SyntaxNode#error?`, diagnostics, and Green error/skipped flags |
|
|
70
|
+
| `CST::Node#symbol`, `#production_id`, `#children`, `#location`, `#trailing_trivia` | root/reduction shape, source position, final trivia | `SyntaxNode#symbol`, `#children`, `#location`, and compatibility `#trailing_trivia`; `#production_id` is the `-1` sentinel because kinds/slot metadata replace occurrence-local production identity |
|
|
71
|
+
| `CST::Node#each`, `#deconstruct`, `#deconstruct_keys`, `#to_h`, `#with_trailing_trivia` | enumeration, pattern matching, final-trivia attachment | Red `Enumerable`/pattern/hash methods; persistent trivia changes use the owning token's `with_leading`/`with_trailing` |
|
|
72
|
+
|
|
73
|
+
Current pure-syntax shape and compatibility accessors are executable in
|
|
74
|
+
`test/codegen/cst_characterization_test.rb`. Rejection of obsolete CST table
|
|
75
|
+
shapes is covered by `test/runtime/table_format_test.rb` and
|
|
76
|
+
`test/codegen/cst_runtime_integration_test.rb`. The semantic-value removal is
|
|
77
|
+
the C1 change; the `source_file` root is C2.
|
|
78
|
+
|
|
79
|
+
## Trivia
|
|
80
|
+
|
|
81
|
+
`--cst-trivia=attach` remains accepted and means `leading`.
|
|
82
|
+
|
|
83
|
+
- `leading`: skipped lexer text belongs to the next token.
|
|
84
|
+
- `balanced`: text through the first newline belongs to the preceding token,
|
|
85
|
+
with the remainder leading the next token.
|
|
86
|
+
- `drop`: trivia is omitted; source-coordinate and incremental APIs raise
|
|
87
|
+
because offsets no longer correspond to the original source.
|
|
88
|
+
|
|
89
|
+
Use `to_source` for a binary-exact reconstruction. On early `yyaccept`,
|
|
90
|
+
`incomplete_input?` is true and `to_source` is the consumed prefix.
|
|
91
|
+
|
|
92
|
+
## Errors and repair
|
|
93
|
+
|
|
94
|
+
Lexical failures, yacc recovery, panic discards, and bounded repair return a
|
|
95
|
+
syntax result rather than changing the semantic action contract. Inspect
|
|
96
|
+
`diagnostics`, `contains_error?`, `each_error`, missing tokens, and Green flags
|
|
97
|
+
for skipped input. Unrecoverable input is retained under `synthetic_root`.
|
|
98
|
+
|
|
99
|
+
## New capabilities
|
|
100
|
+
|
|
101
|
+
Format v6 provides typed `Parser::Syntax` views, persistent
|
|
102
|
+
path-copy editing, annotations, structural text diffing, `ibex_cst` v1
|
|
103
|
+
serialization, and syntax-only incremental sessions. These APIs have no
|
|
104
|
+
equivalent on the removed mixed semantic/syntax tree. Batch CST, views,
|
|
105
|
+
editing, and serialization are Stable; incremental sessions remain
|
|
106
|
+
Experimental. See the [CST guide](cst.md) for examples and the incremental
|
|
107
|
+
action contract.
|