3 Commits
Author SHA1 Message Date
josh 4ec4f40b36 v5.3.0 2026-11-06 08:49:14 -05:00
josh de7c126b31 Update gems 2026-11-06 08:48:09 -05:00
josh e5805d2db4 Warn on unused rules 2026-11-03 22:07:51 -05:00
9 changed files with 118 additions and 25 deletions

No files matched your search

+8
View File
@@ -1,3 +1,11 @@
## v5.3.0
### New Features
- Warn about unused rules (rules not reachable from any start rule). The
warnings are written to the log file and, with `-w`, are printed to stderr
and treated as fatal errors.
## v5.2.0
### New Features
+27 -15
View File
@@ -2,17 +2,27 @@ GEM
remote: https://rubygems.org/
specs:
base64 (0.3.0)
date (3.5.1)
diff-lcs (1.6.2)
docile (1.4.1)
erb (6.0.4)
psych (5.4.0)
date
stringio
erb (6.0.7)
logger (1.7.0)
prism (2.1.0)
prism (2.1.0-aarch64-linux-gnu)
prism (2.1.0-aarch64-linux-musl)
prism (2.1.0-arm-linux-gnu)
prism (2.1.0-arm-linux-musl)
prism (2.1.0-arm64-darwin)
prism (2.1.0-x86_64-darwin)
prism (2.1.0-x86_64-linux-gnu)
prism (2.1.0-x86_64-linux-musl)
rake (13.4.2)
rdoc (7.2.0)
rbs (4.2.0)
logger
prism (>= 1.6.0)
tsort
rdoc (8.1.0)
erb
psych (>= 4.0.0)
prism (>= 1.6.0)
rbs (>= 4.0.0)
tsort
redcarpet (3.6.1)
rspec (3.13.2)
@@ -28,18 +38,20 @@ GEM
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.7)
simplecov (0.22.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
simplecov_json_formatter (~> 0.1)
simplecov-html (0.13.2)
simplecov_json_formatter (0.1.4)
stringio (3.2.0)
simplecov (1.3.2)
syntax (1.2.2)
tsort (0.2.0)
PLATFORMS
aarch64-linux-gnu
aarch64-linux-musl
arm-linux-gnu
arm-linux-musl
arm64-darwin
ruby
x86_64-darwin
x86_64-linux-gnu
x86_64-linux-musl
DEPENDENCIES
base64
+2 -2
View File
@@ -39,8 +39,8 @@ Propane is typically invoked from the command-line as `./propane`.
debugging a grammar.
--version Show program version and exit.
-w Treat warnings as errors. This option will treat shift/reduce
conflicts as fatal errors and will print them to stderr in
addition to the log file.
conflicts and unused rules as fatal errors and will print
them to stderr in addition to the log file.
The user must specify the path to a Propane input grammar file and a path to an
output file.
+2 -2
View File
@@ -43,8 +43,8 @@ Propane is typically invoked from the command-line as `./propane`.
debugging a grammar.
--version Show program version and exit.
-w Treat warnings as errors. This option will treat shift/reduce
conflicts as fatal errors and will print them to stderr in
addition to the log file.
conflicts and unused rules as fatal errors and will print
them to stderr in addition to the log file.
The user must specify the path to a Propane input grammar file and a path to an
output file.
+2 -2
View File
@@ -10,8 +10,8 @@ Options:
debugging a grammar.
--version Show program version and exit.
-w Treat warnings as errors. This option will treat shift/reduce
conflicts as fatal errors and will print them to stderr in
addition to the log file.
conflicts and unused rules as fatal errors and will print
them to stderr in addition to the log file.
EOF
class << self
+29
View File
@@ -50,6 +50,7 @@ class Propane
build_reduce_actions!
build_tables!
check_unused_rules!
write_log!
errormessage = ""
if @errors.size > 0
@@ -68,6 +69,34 @@ class Propane
private
# Record a warning for each user-defined rule that cannot be reached from
# any start rule.
#
# @return [void]
def check_unused_rules!
reachable = Set.new
pending = @grammar.rules[0...@grammar.start_rules.length].map(&:rule_set)
while rule_set = pending.pop
next if reachable.include?(rule_set)
reachable << rule_set
rule_set.rules.each do |rule|
rule.components.each do |component|
if component.is_a?(RuleSet) && !reachable.include?(component)
pending << component
end
end
end
end
@rule_sets.each do |name, rule_set|
# Skip rule sets generated internally (real start rules and optional
# component rules).
next if name.start_with?("$") || rule_set.optional?
unless reachable.include?(rule_set)
@warnings << "Unused rule #{name} (defined on line #{rule_set.rules.first.line_number})"
end
end
end
def build_tables!
@state_table = []
@shift_table = []
+1 -1
View File
@@ -1,3 +1,3 @@
class Propane
VERSION = "5.2.0"
VERSION = "5.3.0"
end
+45 -1
View File
@@ -45,7 +45,7 @@ SimpleCov.start do
# suite. The parts are merged once at the end by the spec Rake task.
coverage_dir(#{"coverage/parts/#{command_name}".inspect})
filters.clear
add_filter do |src|
skip do |src|
!(src.filename[SimpleCov.root])
end
formatter(MyFormatter)
@@ -267,6 +267,50 @@ EOF
expect(File.binread("spec/run/testparser.log")).to match %r{Shift/Reduce conflict \(state \d+\) between token b and rule As2\? \(defined on line 4\)}
end
it "warns on unused rules" do
write_grammar <<EOF
token a;
token b;
Start -> a;
Unused -> b Other?;
Other -> a;
EOF
results = run_propane(capture: true)
expect(results.stderr).to eq ""
expect(results.status).to eq 0
log = File.binread("spec/run/testparser.log")
expect(log).to match %r{Unused rule Unused \(defined on line 4\)}
expect(log).to match %r{Unused rule Other \(defined on line 5\)}
expect(log).to_not match %r{Unused rule (Start|Other\?)}
end
it "errors on unused rules with -w" do
write_grammar <<EOF
token a;
token b;
Start -> a Used;
Used -> b;
Unused -> b;
EOF
results = run_propane(extra_args: %w[-w], capture: true)
expect(results.stderr).to match %r{Unused rule Unused \(defined on line 5\)}
expect(results.stderr).to_not match %r{Unused rule (Start|Used)\b}
expect(results.status).to_not eq 0
end
it "does not warn about rules reachable from any of multiple start rules" do
write_grammar <<EOF
token a;
token b;
start Start Other;
Start -> a;
Other -> b;
EOF
results = run_propane(extra_args: %w[-w], capture: true)
expect(results.stderr).to eq ""
expect(results.status).to eq 0
end
it "errors on duplicate field aliases in a rule" do
write_grammar <<EOF
token a;
+2 -2
View File
@@ -7,8 +7,8 @@ unless ENV["dist_specs"]
end
end
SimpleCov.start do
add_filter "/spec/"
add_filter "/.bundle/"
skip "/spec/"
skip "/.bundle/"
if ENV["partial_specs"]
command_name "RSpec-partial"
else