Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 'only-explicit-rules' option to display explicit grammar rules #496

Merged
merged 3 commits into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions lib/lrama/grammar/rule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 4 additions & 3 deletions lib/lrama/option_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def parse_by_option_parser(argv)
o.on_tail ' automaton display states'
o.on_tail ' closure display states'
o.on_tail ' rules display grammar rules'
o.on_tail ' only-explicit-rules display only explicit grammar rules'
o.on_tail ' actions display grammar rules with actions'
o.on_tail ' time display generation time'
o.on_tail ' all include all the above traces'
Expand Down Expand Up @@ -135,8 +136,8 @@ def aliased_report_option(opt)

VALID_TRACES = %w[
locations scan parse automaton bitsets closure
grammar rules actions resource sets muscles
tools m4-early m4 skeleton time ielr cex
grammar rules only-explicit-rules actions resource
sets muscles tools m4-early m4 skeleton time ielr cex
].freeze
NOT_SUPPORTED_TRACES = %w[
locations scan parse bitsets grammar resource
Expand All @@ -146,7 +147,7 @@ def aliased_report_option(opt)
def validate_trace(trace)
h = {}
return h if trace.empty? || trace == ['none']
supported = VALID_TRACES - NOT_SUPPORTED_TRACES
supported = VALID_TRACES - NOT_SUPPORTED_TRACES - %w[only-explicit-rules]
ydah marked this conversation as resolved.
Show resolved Hide resolved
if trace == ['all']
supported.each { |t| h[t.to_sym] = true }
return h
Expand Down
15 changes: 12 additions & 3 deletions lib/lrama/trace_reporter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ def report(**options)

private

# @rbs rules: (bool rules, bool actions, **untyped _) -> void
def _report(rules: false, actions: false, **_)
report_rules if rules
# @rbs rules: (bool rules, bool actions, bool only_explicit_rules, **untyped _) -> void
def _report(rules: false, actions: false, only_explicit_rules: false, **_)
report_rules if rules && !only_explicit_rules
report_only_explicit_rules if only_explicit_rules
report_actions if actions
end

Expand All @@ -27,6 +28,14 @@ def report_rules
@grammar.rules.each { |rule| puts rule.display_name }
end

# @rbs () -> void
def report_only_explicit_rules
puts "Grammar rules:"
@grammar.rules.each do |rule|
puts rule.display_name_without_action if rule.lhs.first_set.any?
end
end

# @rbs () -> void
def report_actions
puts "Grammar rules with actions:"
Expand Down
7 changes: 5 additions & 2 deletions sig/generated/lrama/trace_reporter.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ module Lrama

private

# @rbs rules: (bool rules, bool actions, **untyped _) -> void
def _report: (?rules: untyped, ?actions: untyped, **untyped _) -> untyped
# @rbs rules: (bool rules, bool actions, bool only_explicit_rules, **untyped _) -> void
def _report: (?rules: untyped, ?actions: untyped, ?only_explicit_rules: untyped, **untyped _) -> untyped

# @rbs () -> void
def report_rules: () -> void

# @rbs () -> void
def report_only_explicit_rules: () -> void

# @rbs () -> void
def report_actions: () -> void
end
Expand Down
1 change: 1 addition & 0 deletions spec/lrama/option_parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
automaton display states
closure display states
rules display grammar rules
only-explicit-rules display only explicit grammar rules
actions display grammar rules with actions
time display generation time
all include all the above traces
Expand Down
102 changes: 102 additions & 0 deletions spec/lrama/trace_reporter_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# 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 and only_explicit_rules: false" do
it "prints the all rules" do
expect do
described_class.new(grammar).report(rules: true, only_explicit_rules: false)
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
$@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
RULES
end
end

context "when rules: true and only_explicit_rules: true" do
it "prints the only explicit rules" do
expect do
described_class.new(grammar).report(rules: true, only_explicit_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
Loading