diff --git a/lib/lrama/command.rb b/lib/lrama/command.rb index 831a709c..4530f27e 100644 --- a/lib/lrama/command.rb +++ b/lib/lrama/command.rb @@ -61,7 +61,7 @@ def run(argv) logger = Lrama::Logger.new exit false unless Lrama::GrammarValidator.new(grammar, states, logger).valid? - Lrama::Diagnostics.new(states, logger).run(**options.diagnostic_opts) + Lrama::Diagnostics.new(grammar, states, logger).run(**options.diagnostic_opts) end end end diff --git a/lib/lrama/diagnostics.rb b/lib/lrama/diagnostics.rb index 42b6f472..1f6f9ed9 100644 --- a/lib/lrama/diagnostics.rb +++ b/lib/lrama/diagnostics.rb @@ -2,13 +2,15 @@ module Lrama class Diagnostics - def initialize(states, logger) + def initialize(grammar, states, logger) + @grammar = grammar @states = states @logger = logger end - def run(conflicts_sr: false, conflicts_rr: false) + def run(conflicts_sr: false, conflicts_rr: false, parameterizing_redefined: false) diagnose_conflict(conflicts_sr, conflicts_rr) + diagnose_parameterizing_redefined if parameterizing_redefined end private @@ -22,5 +24,11 @@ def diagnose_conflict(conflicts_sr, conflicts_rr) @logger.warn("reduce/reduce conflicts: #{@states.rr_conflicts_count} found") end end + + def diagnose_parameterizing_redefined + @grammar.parameterizing_rule_resolver.redefined_rules.each do |rule| + @logger.warn("parameterizing rule redefined: #{rule}") + end + end end end diff --git a/lib/lrama/grammar.rb b/lib/lrama/grammar.rb index 0112f03f..0ba546a1 100644 --- a/lib/lrama/grammar.rb +++ b/lib/lrama/grammar.rb @@ -25,7 +25,7 @@ module Lrama class Grammar extend Forwardable - attr_reader :percent_codes, :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol, :aux + attr_reader :percent_codes, :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol, :aux, :parameterizing_rule_resolver attr_accessor :union, :expect, :printers, :error_tokens, :lex_param, :parse_param, :initial_action, diff --git a/lib/lrama/grammar/parameterizing_rule/resolver.rb b/lib/lrama/grammar/parameterizing_rule/resolver.rb index edd7c918..fede5919 100644 --- a/lib/lrama/grammar/parameterizing_rule/resolver.rb +++ b/lib/lrama/grammar/parameterizing_rule/resolver.rb @@ -27,6 +27,10 @@ def created_lhs(lhs_s_value) @created_lhs_list.reverse.find { |created_lhs| created_lhs.s_value == lhs_s_value } end + def redefined_rules + @rules.select { |rule| @rules.count { |r| r.name == rule.name && r.required_parameters_count == rule.required_parameters_count } > 1 } + end + private def select_rules(rules, token) diff --git a/lib/lrama/grammar/parameterizing_rule/rule.rb b/lib/lrama/grammar/parameterizing_rule/rule.rb index e5dd3d5b..cc200d2f 100644 --- a/lib/lrama/grammar/parameterizing_rule/rule.rb +++ b/lib/lrama/grammar/parameterizing_rule/rule.rb @@ -14,6 +14,10 @@ def initialize(name, parameters, rhs_list, tag: nil, is_inline: false) @is_inline = is_inline @required_parameters_count = parameters.count end + + def to_s + "#{@name}(#{@parameters.map(&:s_value).join(', ')})" + end end end end diff --git a/lib/lrama/option_parser.rb b/lib/lrama/option_parser.rb index c234ab4a..8459e818 100644 --- a/lib/lrama/option_parser.rb +++ b/lib/lrama/option_parser.rb @@ -87,6 +87,7 @@ def parse_by_option_parser(argv) o.separator 'Warning categories include:' o.separator ' conflicts-sr Shift/Reduce conflicts (enabled by default)' o.separator ' conflicts-rr Reduce/Reduce conflicts (enabled by default)' + o.separator ' parameterizing-redefined redefinition of parameterizing rule' o.separator ' all all warnings' o.separator ' none turn off all warnings' o.separator '' @@ -152,7 +153,7 @@ def validate_trace(trace) end DIAGNOSTICS = %w[] - HYPHENATED_DIAGNOSTICS = %w[conflicts-sr conflicts-rr] + HYPHENATED_DIAGNOSTICS = %w[conflicts-sr conflicts-rr parameterizing-redefined] def validate_diagnostic(diagnostic) h = { conflicts_sr: true, conflicts_rr: true } diff --git a/spec/lrama/diagnostics_spec.rb b/spec/lrama/diagnostics_spec.rb index 8c31a857..e2d765e1 100644 --- a/spec/lrama/diagnostics_spec.rb +++ b/spec/lrama/diagnostics_spec.rb @@ -75,10 +75,44 @@ class : keyword_class tSTRING keyword_end %prec tPLUS states.compute logger = Lrama::Logger.new allow(logger).to receive(:warn) - Lrama::Diagnostics.new(states, logger).run(conflicts_sr: true, conflicts_rr: true) + Lrama::Diagnostics.new(grammar, states, logger).run(conflicts_sr: true, conflicts_rr: true) expect(logger).to have_received(:warn).with("shift/reduce conflicts: 2 found") expect(logger).to have_received(:warn).with("reduce/reduce conflicts: 1 found") end end + + context "when rule has parameterizing redefined" do + let(:y) do + <<~STR + %{ + // Prologue + %} + %union { + int i; + } + %token tNUMBER + %rule foo(X) : X + ; + %rule foo(Y) : Y + ; + %% + program: foo(tNUMBER) + ; + STR + end + + it "has warns for parameterizing redefined" do + grammar = Lrama::Parser.new(y, "states/parameterizing_rule_redefined.y").parse + grammar.prepare + grammar.validate! + states = Lrama::States.new(grammar) + states.compute + logger = Lrama::Logger.new + allow(logger).to receive(:warn) + Lrama::Diagnostics.new(grammar, states, logger).run(parameterizing_redefined: true) + expect(logger).to have_received(:warn).with("parameterizing rule redefined: foo(X)") + expect(logger).to have_received(:warn).with("parameterizing rule redefined: foo(Y)") + end + end end end diff --git a/spec/lrama/option_parser_spec.rb b/spec/lrama/option_parser_spec.rb index 9ee19179..270efa06 100644 --- a/spec/lrama/option_parser_spec.rb +++ b/spec/lrama/option_parser_spec.rb @@ -66,6 +66,7 @@ Warning categories include: conflicts-sr Shift/Reduce conflicts (enabled by default) conflicts-rr Reduce/Reduce conflicts (enabled by default) + parameterizing-redefined redefinition of parameterizing rule all all warnings none turn off all warnings