Skip to content

Commit

Permalink
Fix an error when str.length is greater than length
Browse files Browse the repository at this point in the history
This PR fix an error when `str.length` is greater than `length`.
Reproduced by parse.y below:
https://gist.github.com/ydah/70186de8a1ff14fa2cd16b338b9fc0e0
  • Loading branch information
ydah committed Dec 7, 2024
1 parent a7842f8 commit 44be665
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/lrama/counterexamples/derivation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def _render_for_report(derivation, offset, strings, index)
str << "#{item.next_sym.display_name}"
length = _render_for_report(derivation.left, len, strings, index + 1)
# I want String#ljust!
str << " " * (length - str.length)
str << " " * (length - str.length) if length > str.length
else
str << " • #{item.symbols_after_dot.map(&:display_name).join(" ")} "
return str.length
Expand Down
86 changes: 86 additions & 0 deletions spec/lrama/counterexamples_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,92 @@
4: digit '+' digit •
STR
end

context "when the grammar has a long rule name" do
let(:y) do
<<~STR
%{
// Prologue
%}
%union {
int i;
}
%token <i> digit
%type <i> stmt
%type <i> expr1
%type <i> long_long_long_name_expr2
%%
stmt : expr1
| long_long_long_name_expr2
;
expr1 : digit '+' digit
;
long_long_long_name_expr2 : digit '+' digit
;
%%
STR
end

it "build counterexamples of R/R conflicts" do
grammar = Lrama::Parser.new(y, "parse.y").parse
grammar.prepare
grammar.validate!
states = Lrama::States.new(grammar)
states.compute
counterexamples = Lrama::Counterexamples.new(states)

# State 7
#
# 3 expr1: digit '+' digit • ["end of file"]
# 4 long_long_long_name_expr2: digit '+' digit • ["end of file"]
#
# "end of file" reduce using rule 3 (expr1)
# "end of file" reduce using rule 4 (long_long_long_name_expr2)
state_7 = states.states[7]
examples = counterexamples.compute(state_7)
expect(examples.count).to eq 1
example = examples[0]

expect(example.type).to eq :reduce_reduce
# Reduce Conflict
expect(example.path1.map(&:to).map(&:item).map(&:to_s)).to eq([
"$accept: • stmt \"end of file\" (rule 0)",
"stmt: • expr1 (rule 1)",
"expr1: • digit '+' digit (rule 3)",
"expr1: digit • '+' digit (rule 3)",
"expr1: digit '+' • digit (rule 3)",
"expr1: digit '+' digit • (rule 3)"
])
expect(example.derivations1.render_for_report).to eq(<<~STR.chomp)
0: stmt "end of file"
1: expr1
3: digit '+' digit •
STR
# Reduce Conflict
expect(example.path2.map(&:to).map(&:item).map(&:to_s)).to eq([
"$accept: • stmt \"end of file\" (rule 0)",
"stmt: • long_long_long_name_expr2 (rule 2)",
"long_long_long_name_expr2: • digit '+' digit (rule 4)",
"long_long_long_name_expr2: digit • '+' digit (rule 4)",
"long_long_long_name_expr2: digit '+' • digit (rule 4)",
"long_long_long_name_expr2: digit '+' digit • (rule 4)"
])
expect(example.derivations2.render_for_report).to eq(<<~STR.chomp)
0: stmt "end of file"
2: long_long_long_name_expr2
4: digit '+' digit •
STR
end
end
end

describe "target state item will be start item when finding shift conflict shortest state items" do
Expand Down

0 comments on commit 44be665

Please sign in to comment.