From e05bcf835ad558faf98aa16af34dd581da95b933 Mon Sep 17 00:00:00 2001 From: ydah Date: Wed, 1 Jan 2025 11:39:01 +0900 Subject: [PATCH] Do not include mid-rule actions when tracing rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR, midrule actions should not be included when tracing rules. Before: ``` ❯ exe/lrama --trace=rules ./spec/fixtures/common/basic.y Grammar rules: $accept -> program EOI program -> class program -> '+' strings_1 program -> '-' strings_2 class -> keyword_class tSTRING keyword_end $@1 -> ε $@2 -> ε class -> keyword_class $@1 tSTRING '!' keyword_end $@2 $@3 -> ε $@4 -> ε class -> keyword_class $@3 tSTRING '?' keyword_end $@4 strings_1 -> string_1 strings_2 -> string_1 strings_2 -> string_2 string_1 -> string string_2 -> string '+' string -> tSTRING unused -> tNUMBER ``` After: ``` ❯ exe/lrama --trace=rules ./spec/fixtures/common/basic.y Grammar rules: $accept -> program EOI program -> class program -> '+' strings_1 program -> '-' strings_2 class -> keyword_class tSTRING keyword_end class -> keyword_class tSTRING '!' keyword_end class -> keyword_class tSTRING '?' keyword_end strings_1 -> string_1 strings_2 -> string_1 strings_2 -> string_2 string_1 -> string string_2 -> string '+' string -> tSTRING unused -> tNUMBER ``` --- lib/lrama/grammar/rule.rb | 8 ++++ lib/lrama/trace_reporter.rb | 4 +- spec/lrama/trace_reporter_spec.rb | 74 +++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 spec/lrama/trace_reporter_spec.rb diff --git a/lib/lrama/grammar/rule.rb b/lib/lrama/grammar/rule.rb index 1f55bf8b..445752ae 100644 --- a/lib/lrama/grammar/rule.rb +++ b/lib/lrama/grammar/rule.rb @@ -21,6 +21,14 @@ def ==(other) def display_name l = lhs.id.s_value r = empty_rule? ? "ε" : rhs.map {|r| r.id.s_value }.join(" ") + "#{l} -> #{r}" + end + + def display_name_without_action + l = lhs.id.s_value + r = empty_rule? ? "ε" : rhs.map do |r| + r.id.s_value if r.first_set.any? + end.compact.join(" ") "#{l} -> #{r}" end diff --git a/lib/lrama/trace_reporter.rb b/lib/lrama/trace_reporter.rb index 87c01a4c..48aa5d0e 100644 --- a/lib/lrama/trace_reporter.rb +++ b/lib/lrama/trace_reporter.rb @@ -19,7 +19,9 @@ def _report(rules: false, actions: false, **_) def report_rules puts "Grammar rules:" - @grammar.rules.each { |rule| puts rule.display_name } + @grammar.rules.each do |rule| + puts rule.display_name_without_action if rule.lhs.first_set.any? + end end def report_actions diff --git a/spec/lrama/trace_reporter_spec.rb b/spec/lrama/trace_reporter_spec.rb new file mode 100644 index 00000000..134a0d79 --- /dev/null +++ b/spec/lrama/trace_reporter_spec.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +RSpec.describe Lrama::TraceReporter do + describe "#report" do + let(:path) { "common/basic.y" } + let(:y) { File.read(fixture_path(path)) } + let(:grammar) do + grammar = Lrama::Parser.new(y, path).parse + grammar.prepare + grammar.validate! + grammar + end + + context "when rules: true" do + it "prints the rules" do + expect do + described_class.new(grammar).report(rules: true) + end.to output(<<~RULES).to_stdout + Grammar rules: + $accept -> program EOI + program -> class + program -> '+' strings_1 + program -> '-' strings_2 + class -> keyword_class tSTRING keyword_end + class -> keyword_class tSTRING '!' keyword_end + class -> keyword_class tSTRING '?' keyword_end + strings_1 -> string_1 + strings_2 -> string_1 + strings_2 -> string_2 + string_1 -> string + string_2 -> string '+' + string -> tSTRING + unused -> tNUMBER + RULES + end + end + + context "when actions: true" do + it "prints the actions" do + expect do + described_class.new(grammar).report(actions: true) + end.to output(<<~RULES).to_stdout + Grammar rules with actions: + $accept -> program EOI {} + program -> class {} + program -> '+' strings_1 {} + program -> '-' strings_2 {} + class -> keyword_class tSTRING keyword_end { code 1 } + $@1 -> ε { code 2 } + $@2 -> ε { code 3 } + class -> keyword_class $@1 tSTRING '!' keyword_end $@2 {} + $@3 -> ε { code 4 } + $@4 -> ε { code 5 } + class -> keyword_class $@3 tSTRING '?' keyword_end $@4 {} + strings_1 -> string_1 {} + strings_2 -> string_1 {} + strings_2 -> string_2 {} + string_1 -> string {} + string_2 -> string '+' {} + string -> tSTRING {} + unused -> tNUMBER {} + RULES + end + end + + context 'when empty options' do + it 'does not print anything' do + expect do + described_class.new(grammar).report + end.to_not output.to_stdout + end + end + end +end