Skip to content

Commit 5d80bc5

Browse files
Earlopainkddnewton
authored andcommitted
Correctly handle and? and similar on ruby 4.0
It gets confused for syntax introduced in https://bugs.ruby-lang.org/issues/20925 But it actually should be a plain method call. `!`/`?` are not valid as part of an identifier, methods however allow them as the last character. Fixes [Bug #21946]
1 parent d4575f6 commit 5d80bc5

File tree

6 files changed

+204
-57
lines changed

6 files changed

+204
-57
lines changed

snapshots/4.0/leading_logical.txt

Lines changed: 22 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
@ ProgramNode (location: (1,0)-(21,5))
1+
@ ProgramNode (location: (1,0)-(15,4))
22
├── flags: ∅
33
├── locals: []
44
└── statements:
5-
@ StatementsNode (location: (1,0)-(21,5))
5+
@ StatementsNode (location: (1,0)-(15,4))
66
├── flags: ∅
7-
└── body: (length: 8)
7+
└── body: (length: 4)
88
├── @ AndNode (location: (1,0)-(3,4))
99
│ ├── flags: newline
1010
│ ├── left:
@@ -62,50 +62,22 @@
6262
│ │ ├── flags: static_literal, decimal
6363
│ │ └── value: 3
6464
│ └── operator_loc: (11,0)-(11,3) = "and"
65-
├── @ OrNode (location: (13,0)-(15,4))
66-
│ ├── flags: newline
67-
│ ├── left:
68-
│ │ @ OrNode (location: (13,0)-(14,4))
69-
│ │ ├── flags: ∅
70-
│ │ ├── left:
71-
│ │ │ @ IntegerNode (location: (13,0)-(13,1))
72-
│ │ │ ├── flags: static_literal, decimal
73-
│ │ │ └── value: 1
74-
│ │ ├── right:
75-
│ │ │ @ IntegerNode (location: (14,3)-(14,4))
76-
│ │ │ ├── flags: static_literal, decimal
77-
│ │ │ └── value: 2
78-
│ │ └── operator_loc: (14,0)-(14,2) = "or"
79-
│ ├── right:
80-
│ │ @ IntegerNode (location: (15,3)-(15,4))
81-
│ │ ├── flags: static_literal, decimal
82-
│ │ └── value: 3
83-
│ └── operator_loc: (15,0)-(15,2) = "or"
84-
├── @ IntegerNode (location: (17,0)-(17,1))
85-
│ ├── flags: newline, static_literal, decimal
86-
│ └── value: 1
87-
├── @ CallNode (location: (18,0)-(18,6))
88-
│ ├── flags: newline, variable_call, ignore_visibility
89-
│ ├── receiver: ∅
90-
│ ├── call_operator_loc: ∅
91-
│ ├── name: :andfoo
92-
│ ├── message_loc: (18,0)-(18,6) = "andfoo"
93-
│ ├── opening_loc: ∅
94-
│ ├── arguments: ∅
95-
│ ├── closing_loc: ∅
96-
│ ├── equal_loc: ∅
97-
│ └── block: ∅
98-
├── @ IntegerNode (location: (20,0)-(20,1))
99-
│ ├── flags: newline, static_literal, decimal
100-
│ └── value: 2
101-
└── @ CallNode (location: (21,0)-(21,5))
102-
├── flags: newline, variable_call, ignore_visibility
103-
├── receiver: ∅
104-
├── call_operator_loc: ∅
105-
├── name: :orfoo
106-
├── message_loc: (21,0)-(21,5) = "orfoo"
107-
├── opening_loc: ∅
108-
├── arguments: ∅
109-
├── closing_loc: ∅
110-
├── equal_loc: ∅
111-
└── block: ∅
65+
└── @ OrNode (location: (13,0)-(15,4))
66+
├── flags: newline
67+
├── left:
68+
│ @ OrNode (location: (13,0)-(14,4))
69+
│ ├── flags: ∅
70+
│ ├── left:
71+
│ │ @ IntegerNode (location: (13,0)-(13,1))
72+
│ │ ├── flags: static_literal, decimal
73+
│ │ └── value: 1
74+
│ ├── right:
75+
│ │ @ IntegerNode (location: (14,3)-(14,4))
76+
│ │ ├── flags: static_literal, decimal
77+
│ │ └── value: 2
78+
│ └── operator_loc: (14,0)-(14,2) = "or"
79+
├── right:
80+
│ @ IntegerNode (location: (15,3)-(15,4))
81+
│ ├── flags: static_literal, decimal
82+
│ └── value: 3
83+
└── operator_loc: (15,0)-(15,2) = "or"

snapshots/and_or_with_suffix.txt

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
@ ProgramNode (location: (1,0)-(17,5))
2+
├── flags: ∅
3+
├── locals: []
4+
└── statements:
5+
@ StatementsNode (location: (1,0)-(17,5))
6+
├── flags: ∅
7+
└── body: (length: 12)
8+
├── @ CallNode (location: (1,0)-(1,3))
9+
│ ├── flags: newline, variable_call, ignore_visibility
10+
│ ├── receiver: ∅
11+
│ ├── call_operator_loc: ∅
12+
│ ├── name: :foo
13+
│ ├── message_loc: (1,0)-(1,3) = "foo"
14+
│ ├── opening_loc: ∅
15+
│ ├── arguments: ∅
16+
│ ├── closing_loc: ∅
17+
│ ├── equal_loc: ∅
18+
│ └── block: ∅
19+
├── @ CallNode (location: (2,0)-(2,4))
20+
│ ├── flags: newline, ignore_visibility
21+
│ ├── receiver: ∅
22+
│ ├── call_operator_loc: ∅
23+
│ ├── name: :and?
24+
│ ├── message_loc: (2,0)-(2,4) = "and?"
25+
│ ├── opening_loc: ∅
26+
│ ├── arguments: ∅
27+
│ ├── closing_loc: ∅
28+
│ ├── equal_loc: ∅
29+
│ └── block: ∅
30+
├── @ CallNode (location: (4,0)-(4,3))
31+
│ ├── flags: newline, variable_call, ignore_visibility
32+
│ ├── receiver: ∅
33+
│ ├── call_operator_loc: ∅
34+
│ ├── name: :foo
35+
│ ├── message_loc: (4,0)-(4,3) = "foo"
36+
│ ├── opening_loc: ∅
37+
│ ├── arguments: ∅
38+
│ ├── closing_loc: ∅
39+
│ ├── equal_loc: ∅
40+
│ └── block: ∅
41+
├── @ CallNode (location: (5,0)-(5,3))
42+
│ ├── flags: newline, ignore_visibility
43+
│ ├── receiver: ∅
44+
│ ├── call_operator_loc: ∅
45+
│ ├── name: :or?
46+
│ ├── message_loc: (5,0)-(5,3) = "or?"
47+
│ ├── opening_loc: ∅
48+
│ ├── arguments: ∅
49+
│ ├── closing_loc: ∅
50+
│ ├── equal_loc: ∅
51+
│ └── block: ∅
52+
├── @ CallNode (location: (7,0)-(7,3))
53+
│ ├── flags: newline, variable_call, ignore_visibility
54+
│ ├── receiver: ∅
55+
│ ├── call_operator_loc: ∅
56+
│ ├── name: :foo
57+
│ ├── message_loc: (7,0)-(7,3) = "foo"
58+
│ ├── opening_loc: ∅
59+
│ ├── arguments: ∅
60+
│ ├── closing_loc: ∅
61+
│ ├── equal_loc: ∅
62+
│ └── block: ∅
63+
├── @ CallNode (location: (8,0)-(8,4))
64+
│ ├── flags: newline, ignore_visibility
65+
│ ├── receiver: ∅
66+
│ ├── call_operator_loc: ∅
67+
│ ├── name: :and!
68+
│ ├── message_loc: (8,0)-(8,4) = "and!"
69+
│ ├── opening_loc: ∅
70+
│ ├── arguments: ∅
71+
│ ├── closing_loc: ∅
72+
│ ├── equal_loc: ∅
73+
│ └── block: ∅
74+
├── @ CallNode (location: (10,0)-(10,3))
75+
│ ├── flags: newline, variable_call, ignore_visibility
76+
│ ├── receiver: ∅
77+
│ ├── call_operator_loc: ∅
78+
│ ├── name: :foo
79+
│ ├── message_loc: (10,0)-(10,3) = "foo"
80+
│ ├── opening_loc: ∅
81+
│ ├── arguments: ∅
82+
│ ├── closing_loc: ∅
83+
│ ├── equal_loc: ∅
84+
│ └── block: ∅
85+
├── @ CallNode (location: (11,0)-(11,3))
86+
│ ├── flags: newline, ignore_visibility
87+
│ ├── receiver: ∅
88+
│ ├── call_operator_loc: ∅
89+
│ ├── name: :or!
90+
│ ├── message_loc: (11,0)-(11,3) = "or!"
91+
│ ├── opening_loc: ∅
92+
│ ├── arguments: ∅
93+
│ ├── closing_loc: ∅
94+
│ ├── equal_loc: ∅
95+
│ └── block: ∅
96+
├── @ CallNode (location: (13,0)-(13,3))
97+
│ ├── flags: newline, variable_call, ignore_visibility
98+
│ ├── receiver: ∅
99+
│ ├── call_operator_loc: ∅
100+
│ ├── name: :foo
101+
│ ├── message_loc: (13,0)-(13,3) = "foo"
102+
│ ├── opening_loc: ∅
103+
│ ├── arguments: ∅
104+
│ ├── closing_loc: ∅
105+
│ ├── equal_loc: ∅
106+
│ └── block: ∅
107+
├── @ CallNode (location: (14,0)-(14,6))
108+
│ ├── flags: newline, variable_call, ignore_visibility
109+
│ ├── receiver: ∅
110+
│ ├── call_operator_loc: ∅
111+
│ ├── name: :andbar
112+
│ ├── message_loc: (14,0)-(14,6) = "andbar"
113+
│ ├── opening_loc: ∅
114+
│ ├── arguments: ∅
115+
│ ├── closing_loc: ∅
116+
│ ├── equal_loc: ∅
117+
│ └── block: ∅
118+
├── @ CallNode (location: (16,0)-(16,3))
119+
│ ├── flags: newline, variable_call, ignore_visibility
120+
│ ├── receiver: ∅
121+
│ ├── call_operator_loc: ∅
122+
│ ├── name: :foo
123+
│ ├── message_loc: (16,0)-(16,3) = "foo"
124+
│ ├── opening_loc: ∅
125+
│ ├── arguments: ∅
126+
│ ├── closing_loc: ∅
127+
│ ├── equal_loc: ∅
128+
│ └── block: ∅
129+
└── @ CallNode (location: (17,0)-(17,5))
130+
├── flags: newline, variable_call, ignore_visibility
131+
├── receiver: ∅
132+
├── call_operator_loc: ∅
133+
├── name: :orbar
134+
├── message_loc: (17,0)-(17,5) = "orbar"
135+
├── opening_loc: ∅
136+
├── arguments: ∅
137+
├── closing_loc: ∅
138+
├── equal_loc: ∅
139+
└── block: ∅

src/prism.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10034,8 +10034,21 @@ parser_lex(pm_parser_t *parser) {
1003410034
following && (
1003510035
(peek_at(parser, following) == '&' && peek_at(parser, following + 1) == '&') ||
1003610036
(peek_at(parser, following) == '|' && peek_at(parser, following + 1) == '|') ||
10037-
(peek_at(parser, following) == 'a' && peek_at(parser, following + 1) == 'n' && peek_at(parser, following + 2) == 'd' && !char_is_identifier(parser, following + 3, parser->end - (following + 3))) ||
10038-
(peek_at(parser, following) == 'o' && peek_at(parser, following + 1) == 'r' && !char_is_identifier(parser, following + 2, parser->end - (following + 2)))
10037+
(
10038+
peek_at(parser, following) == 'a' &&
10039+
peek_at(parser, following + 1) == 'n' &&
10040+
peek_at(parser, following + 2) == 'd' &&
10041+
peek_at(parser, next_content + 3) != '!' &&
10042+
peek_at(parser, next_content + 3) != '?' &&
10043+
!char_is_identifier(parser, following + 3, parser->end - (following + 3))
10044+
) ||
10045+
(
10046+
peek_at(parser, following) == 'o' &&
10047+
peek_at(parser, following + 1) == 'r' &&
10048+
peek_at(parser, next_content + 2) != '!' &&
10049+
peek_at(parser, next_content + 2) != '?' &&
10050+
!char_is_identifier(parser, following + 2, parser->end - (following + 2))
10051+
)
1003910052
)
1004010053
) {
1004110054
if (!lexed_comment) parser_lex_ignored_newline(parser);
@@ -10106,6 +10119,8 @@ parser_lex(pm_parser_t *parser) {
1010610119
peek_at(parser, next_content) == 'a' &&
1010710120
peek_at(parser, next_content + 1) == 'n' &&
1010810121
peek_at(parser, next_content + 2) == 'd' &&
10122+
peek_at(parser, next_content + 3) != '!' &&
10123+
peek_at(parser, next_content + 3) != '?' &&
1010910124
!char_is_identifier(parser, next_content + 3, parser->end - (next_content + 3))
1011010125
) {
1011110126
if (!lexed_comment) parser_lex_ignored_newline(parser);
@@ -10122,6 +10137,8 @@ parser_lex(pm_parser_t *parser) {
1012210137
if (
1012310138
peek_at(parser, next_content) == 'o' &&
1012410139
peek_at(parser, next_content + 1) == 'r' &&
10140+
peek_at(parser, next_content + 2) != '!' &&
10141+
peek_at(parser, next_content + 2) != '?' &&
1012510142
!char_is_identifier(parser, next_content + 2, parser->end - (next_content + 2))
1012610143
) {
1012710144
if (!lexed_comment) parser_lex_ignored_newline(parser);

test/prism/fixtures/4.0/leading_logical.txt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,3 @@ and 3
1414
or 2
1515
or 3
1616

17-
1
18-
andfoo
19-
20-
2
21-
orfoo
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
foo
2+
and?
3+
4+
foo
5+
or?
6+
7+
foo
8+
and!
9+
10+
foo
11+
or!
12+
13+
foo
14+
andbar
15+
16+
foo
17+
orbar

test/prism/ruby/ripper_test.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ class RipperTest < TestCase
3737
]
3838
end
3939

40+
if RUBY_VERSION.start_with?("4.")
41+
incorrect += [
42+
# https://bugs.ruby-lang.org/issues/21945
43+
"and_or_with_suffix.txt",
44+
]
45+
end
46+
4047
# https://bugs.ruby-lang.org/issues/21669
4148
incorrect << "4.1/void_value.txt"
4249
# https://bugs.ruby-lang.org/issues/19107

0 commit comments

Comments
 (0)