Skip to content

Commit 555ecec

Browse files
authored
- Fix an error for flip-flop with beginless or endless ranges (#946)
This PR resolves rubocop/rubocop#12198. ```console $ ruby-parse -e 'if foo..; end' Failed on: (fragment:0) /Users/koic/.rbenv/versions/3.3.0-dev/lib/ruby/gems/3.3.0+0/gems/parser-3.2.2.3/lib/parser/builders/default.rb:1676: in `check_condition': undefined method `type' for nil (NoMethodError) case cond.type ^^^^^ from /Users/koic/.rbenv/versions/3.3.0-dev/lib/ruby/gems/3.3.0+0/gems/parser-3.2.2.3/lib/parser/builders/default.rb:1707: in `check_condition' from /Users/koic/.rbenv/versions/3.3.0-dev/lib/ruby/gems/3.3.0+0/gems/parser-3.2.2.3/lib/parser/builders/default.rb:1275: in `condition' ``` I'm not sure if there's any significance to using the flip-flop syntax with `nil`, but by using beginless or endless ranges and explicitly specifying `nil`, the following current behaviors are made compatible: ## `iflipflop` with explicitly `nil` ```console $ ruby-parse -e 'if foo..nil ; end' (if (iflipflop (send nil :foo) (nil)) nil nil) ``` ```console $ ruby-parse -e 'if nil..bar ; end' (if (iflipflop (nil) (send nil :bar)) nil nil) ``` ## `eflipflop` with explicitly `nil` ```console $ ruby-parse -e 'if foo...nil ; end' (if (eflipflop (send nil :foo) (nil)) nil nil) ``` ```console $ ruby-parse -e 'if nil...bar ; end' (if (eflipflop (nil) (send nil :bar)) nil nil) ``` The difference in the flip-flop with beginless or endless ranges is that `s(:nil)` is replaced by `nil` in the flip-flop ASTs. This is reflected in the tests.
1 parent a9c45c5 commit 555ecec

File tree

2 files changed

+91
-9
lines changed

2 files changed

+91
-9
lines changed

lib/parser/builders/default.rb

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1690,24 +1690,34 @@ def check_condition(cond)
16901690
cond
16911691
end
16921692

1693-
when :and, :or, :irange, :erange
1693+
when :and, :or
16941694
lhs, rhs = *cond
16951695

1696-
type = case cond.type
1697-
when :irange then :iflipflop
1698-
when :erange then :eflipflop
1699-
end
1700-
1701-
if [:and, :or].include?(cond.type) &&
1702-
@parser.version == 18
1696+
if @parser.version == 18
17031697
cond
17041698
else
1705-
cond.updated(type, [
1699+
cond.updated(cond.type, [
17061700
check_condition(lhs),
17071701
check_condition(rhs)
17081702
])
17091703
end
17101704

1705+
when :irange, :erange
1706+
lhs, rhs = *cond
1707+
1708+
type = case cond.type
1709+
when :irange then :iflipflop
1710+
when :erange then :eflipflop
1711+
end
1712+
1713+
lhs_condition = check_condition(lhs) unless lhs.nil?
1714+
rhs_condition = check_condition(rhs) unless rhs.nil?
1715+
1716+
return cond.updated(type, [
1717+
lhs_condition,
1718+
rhs_condition
1719+
])
1720+
17111721
when :regexp
17121722
n(:match_current_line, [ cond ], expr_map(cond.loc.expression))
17131723

test/test_parser.rb

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4739,6 +4739,22 @@ def test_cond_iflipflop
47394739
%q{ ~~~~~~~~ expression (iflipflop)
47404740
| ~~ operator (iflipflop)})
47414741

4742+
assert_parses(
4743+
s(:if, s(:iflipflop, s(:lvar, :foo), s(:nil)),
4744+
nil, nil),
4745+
%q{if foo..nil; end},
4746+
%q{ ~~~~~~~~ expression (iflipflop)
4747+
| ~~ operator (iflipflop)},
4748+
%w(1.8))
4749+
4750+
assert_parses(
4751+
s(:if, s(:iflipflop, s(:nil), s(:lvar, :bar)),
4752+
nil, nil),
4753+
%q{if nil..bar; end},
4754+
%q{ ~~~~~~~~ expression (iflipflop)
4755+
| ~~ operator (iflipflop)},
4756+
%w(1.8))
4757+
47424758
assert_parses(
47434759
s(:not, s(:begin, s(:iflipflop, s(:lvar, :foo), s(:lvar, :bar)))),
47444760
%q{!(foo..bar)},
@@ -4754,6 +4770,26 @@ def test_cond_iflipflop
47544770
SINCE_1_9)
47554771
end
47564772

4773+
def test_cond_iflipflop_with_endless_range
4774+
assert_parses(
4775+
s(:if, s(:iflipflop, s(:lvar, :foo), nil),
4776+
nil, nil),
4777+
%q{if foo..; end},
4778+
%q{ ~~~~~ expression (iflipflop)
4779+
| ~~ operator (iflipflop)},
4780+
SINCE_2_6)
4781+
end
4782+
4783+
def test_cond_iflipflop_with_beginless_range
4784+
assert_parses(
4785+
s(:if, s(:iflipflop, nil, s(:lvar, :bar)),
4786+
nil, nil),
4787+
%q{if ..bar; end},
4788+
%q{ ~~~~~ expression (iflipflop)
4789+
| ~~ operator (iflipflop)},
4790+
SINCE_2_7)
4791+
end
4792+
47574793
def test_cond_eflipflop
47584794
assert_parses(
47594795
s(:if, s(:eflipflop, s(:lvar, :foo), s(:lvar, :bar)),
@@ -4762,6 +4798,22 @@ def test_cond_eflipflop
47624798
%q{ ~~~~~~~~~ expression (eflipflop)
47634799
| ~~~ operator (eflipflop)})
47644800

4801+
assert_parses(
4802+
s(:if, s(:eflipflop, s(:lvar, :foo), s(:nil)),
4803+
nil, nil),
4804+
%q{if foo...nil; end},
4805+
%q{ ~~~~~~~~~ expression (eflipflop)
4806+
| ~~~ operator (eflipflop)},
4807+
%w(1.8))
4808+
4809+
assert_parses(
4810+
s(:if, s(:eflipflop, s(:nil), s(:lvar, :bar)),
4811+
nil, nil),
4812+
%q{if nil...bar; end},
4813+
%q{ ~~~~~~~~~ expression (eflipflop)
4814+
| ~~~ operator (eflipflop)},
4815+
%w(1.8))
4816+
47654817
assert_parses(
47664818
s(:not, s(:begin, s(:eflipflop, s(:lvar, :foo), s(:lvar, :bar)))),
47674819
%q{!(foo...bar)},
@@ -4777,6 +4829,26 @@ def test_cond_eflipflop
47774829
SINCE_1_9)
47784830
end
47794831

4832+
def test_cond_eflipflop_with_endless_range
4833+
assert_parses(
4834+
s(:if, s(:eflipflop, s(:lvar, :foo), nil),
4835+
nil, nil),
4836+
%q{if foo...; end},
4837+
%q{ ~~~~~~ expression (eflipflop)
4838+
| ~~~ operator (eflipflop)},
4839+
SINCE_2_6)
4840+
end
4841+
4842+
def test_cond_eflipflop_with_beginless_range
4843+
assert_parses(
4844+
s(:if, s(:eflipflop, nil, s(:lvar, :bar)),
4845+
nil, nil),
4846+
%q{if ...bar; end},
4847+
%q{ ~~~~~~ expression (eflipflop)
4848+
| ~~~ operator (eflipflop)},
4849+
SINCE_2_7)
4850+
end
4851+
47804852
def test_cond_match_current_line
47814853
assert_parses(
47824854
s(:if,

0 commit comments

Comments
 (0)