Skip to content

Commit 37da43e

Browse files
authored
Merge pull request #755 from ydah/use-%empty-warning
Add support warning [-Wempty-rule]
2 parents 054a91c + 021bf0c commit 37da43e

File tree

4 files changed

+98
-0
lines changed

4 files changed

+98
-0
lines changed

lib/lrama/warnings.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# frozen_string_literal: true
33

44
require_relative 'warnings/conflicts'
5+
require_relative 'warnings/implicit_empty'
56
require_relative 'warnings/redefined_rules'
67
require_relative 'warnings/required'
78
require_relative 'warnings/useless_precedence'
@@ -11,6 +12,7 @@ class Warnings
1112
# @rbs (Logger logger, bool warnings) -> void
1213
def initialize(logger, warnings)
1314
@conflicts = Conflicts.new(logger, warnings)
15+
@implicit_empty = ImplicitEmpty.new(logger, warnings)
1416
@redefined_rules = RedefinedRules.new(logger, warnings)
1517
@required = Required.new(logger, warnings)
1618
@useless_precedence = UselessPrecedence.new(logger, warnings)
@@ -19,6 +21,7 @@ def initialize(logger, warnings)
1921
# @rbs (Lrama::Grammar grammar, Lrama::States states) -> void
2022
def warn(grammar, states)
2123
@conflicts.warn(states)
24+
@implicit_empty.warn(grammar)
2225
@redefined_rules.warn(grammar)
2326
@required.warn(grammar)
2427
@useless_precedence.warn(grammar, states)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# rbs_inline: enabled
2+
# frozen_string_literal: true
3+
4+
module Lrama
5+
class Warnings
6+
# Warning rationale: Empty rules are easily overlooked and ambiguous
7+
# - Empty alternatives like `rule: | "token";` can be missed during code reading
8+
# - Difficult to distinguish between intentional empty rules vs. omissions
9+
# - Explicit marking with %empty directive comment improves clarity
10+
class ImplicitEmpty
11+
# @rbs (Lrama::Logger logger, bool warnings) -> void
12+
def initialize(logger, warnings)
13+
@logger = logger
14+
@warnings = warnings
15+
end
16+
17+
# @rbs (Lrama::Grammar grammar) -> void
18+
def warn(grammar)
19+
return unless @warnings
20+
21+
grammar.rule_builders.each do |builder|
22+
if builder.rhs.empty?
23+
@logger.warn("warning: empty rule without %empty")
24+
end
25+
end
26+
end
27+
end
28+
end
29+
end
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Generated from lib/lrama/warnings/implicit_empty.rb with RBS::Inline
2+
3+
module Lrama
4+
class Warnings
5+
# Warning rationale: Empty rules are easily overlooked and ambiguous
6+
# - Empty alternatives like `rule: | "token";` can be missed during code reading
7+
# - Difficult to distinguish between intentional empty rules vs. omissions
8+
# - Explicit marking with %empty directive comment improves clarity
9+
class ImplicitEmpty
10+
# @rbs (Lrama::Logger logger, bool warnings) -> void
11+
def initialize: (Lrama::Logger logger, bool warnings) -> void
12+
13+
# @rbs (Lrama::Grammar grammar) -> void
14+
def warn: (Lrama::Grammar grammar) -> void
15+
end
16+
end
17+
end
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe Lrama::Warnings::ImplicitEmpty do
4+
describe "#warn" do
5+
let(:y) do
6+
<<~STR
7+
%{
8+
// Prologue
9+
%}
10+
%union {
11+
int i;
12+
}
13+
%token <i> tNUMBER
14+
%%
15+
program: /* empty */
16+
| tNUMBER
17+
;
18+
STR
19+
end
20+
21+
context "when warnings true" do
22+
it "has warns for parameterized rule redefined" do
23+
grammar = Lrama::Parser.new(y, "states/empty.y").parse
24+
grammar.prepare
25+
grammar.validate!
26+
states = Lrama::States.new(grammar, Lrama::Tracer.new(Lrama::Logger.new))
27+
states.compute
28+
logger = Lrama::Logger.new
29+
allow(logger).to receive(:warn)
30+
Lrama::Warnings.new(logger, true).warn(grammar, states)
31+
expect(logger).to have_received(:warn).with("warning: empty rule without %empty")
32+
end
33+
end
34+
35+
context "when warnings false" do
36+
it "has not warns for parameterized rule redefined" do
37+
grammar = Lrama::Parser.new(y, "states/empty.y").parse
38+
grammar.prepare
39+
grammar.validate!
40+
states = Lrama::States.new(grammar, Lrama::Tracer.new(Lrama::Logger.new))
41+
states.compute
42+
logger = Lrama::Logger.new
43+
allow(logger).to receive(:warn)
44+
Lrama::Warnings.new(logger, false).warn(grammar, states)
45+
expect(logger).not_to have_received(:warn).with("warning: empty rule without %empty")
46+
end
47+
end
48+
end
49+
end

0 commit comments

Comments
 (0)