Skip to content

Commit 07e63f7

Browse files
committed
Parse rescue modifier values as statements
The value of a `rescue` modifier is a full `stmt` in the grammar in three of its six productions, but we parsed it as a plain expression in every case. This rejected valid syntax such as `a rescue b, c = 1` and accepted invalid syntax such as `a = 1 rescue not b`. These are the relevant grammar rules: stmt : stmt modifier_rescue stmt | mlhs '=' mrhs_arg modifier_rescue stmt command_rhs : command_call_value modifier_rescue stmt arg_rhs : arg modifier_rescue arg endless_arg : endless_arg modifier_rescue arg endless_command : endless_command modifier_rescue arg parse_rescue_modifier_value will now parse either a stmt or an arg depending on the caller.
1 parent 69a9a36 commit 07e63f7

22 files changed

Lines changed: 2008 additions & 47 deletions

lib/prism/translation/parser/lexer.rb

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -192,17 +192,25 @@ class Lexer # :nodoc:
192192
EXPR_BEG = 0x1
193193
EXPR_LABEL = 0x400
194194

195-
# It is used to determine whether `do` is of the token type `kDO` or `kDO_LAMBDA`.
195+
# It is used to determine whether `do` is of the token type `kDO` or
196+
# `kDO_LAMBDA`.
196197
#
197-
# NOTE: In edge cases like `-> (foo = -> (bar) {}) do end`, please note that `kDO` is still returned
198-
# instead of `kDO_LAMBDA`, which is expected: https://github.com/ruby/prism/pull/3046
198+
# NOTE: In edge cases like `-> (foo = -> (bar) {}) do end`, please note
199+
# that `kDO` is still returned instead of `kDO_LAMBDA`, which is
200+
# expected: https://github.com/ruby/prism/pull/3046
199201
LAMBDA_TOKEN_TYPES = Set.new([:kDO_LAMBDA, :tLAMBDA, :tLAMBEG])
200202

201-
# The `PARENTHESIS_LEFT` token in Prism is classified as either `tLPAREN` or `tLPAREN2` in the Parser gem.
202-
# The following token types are listed as those classified as `tLPAREN`.
203+
# The `PARENTHESIS_LEFT` token in Prism is classified as either
204+
# `tLPAREN` or `tLPAREN2` in the Parser gem. The following token types
205+
# are listed as those classified as `tLPAREN`.
203206
LPAREN_CONVERSION_TOKEN_TYPES = Set.new([
204-
:kBREAK, :tCARET, :kCASE, :tDIVIDE, :kFOR, :kIF, :kNEXT, :kRETURN, :kUNTIL, :kWHILE, :tAMPER, :tANDOP, :tBANG, :tCOMMA, :tDOT2, :tDOT3,
205-
:tEQL, :tLPAREN, :tLPAREN2, :tLPAREN_ARG, :tLSHFT, :tNL, :tOP_ASGN, :tOROP, :tPIPE, :tSEMI, :tSTRING_DBEG, :tUMINUS, :tUPLUS, :tLCURLY
207+
:kAND, :kBEGIN, :kBREAK, :kCASE, :kDO_COND, :kDO_LAMBDA, :kDO, :kELSE,
208+
:kELSIF, :kENSURE, :kFOR, :kIF_MOD, :kIF, :kIN, :kNEXT, :kOR,
209+
:kRESCUE_MOD, :kRESCUE, :kRETURN, :kTHEN, :kUNLESS_MOD, :kUNLESS,
210+
:kUNTIL_MOD, :kUNTIL, :kWHEN, :kWHILE_MOD, :kWHILE,
211+
:tAMPER, :tANDOP, :tBANG, :tCARET, :tCOMMA, :tDIVIDE, :tDOT2, :tDOT3,
212+
:tEQL, :tLCURLY, :tLPAREN_ARG, :tLPAREN, :tLPAREN2, :tLSHFT, :tNL,
213+
:tOP_ASGN, :tOROP, :tPIPE, :tSEMI, :tSTRING_DBEG, :tUMINUS, :tUPLUS
206214
])
207215

208216
# Types of tokens that are allowed to continue a method call with comments in-between.
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
@ ProgramNode (location: (1,0)-(3,23))
2+
├── flags: ∅
3+
├── locals: [:x, :y, :a, :b, :c]
4+
└── statements:
5+
@ StatementsNode (location: (1,0)-(3,23))
6+
├── flags: ∅
7+
└── body: (length: 3)
8+
├── @ MultiWriteNode (location: (1,0)-(1,24))
9+
│ ├── flags: newline
10+
│ ├── lefts: (length: 2)
11+
│ │ ├── @ LocalVariableTargetNode (location: (1,0)-(1,1))
12+
│ │ │ ├── flags: ∅
13+
│ │ │ ├── name: :x
14+
│ │ │ └── depth: 0
15+
│ │ └── @ LocalVariableTargetNode (location: (1,3)-(1,4))
16+
│ │ ├── flags: ∅
17+
│ │ ├── name: :y
18+
│ │ └── depth: 0
19+
│ ├── rest: ∅
20+
│ ├── rights: (length: 0)
21+
│ ├── lparen_loc: ∅
22+
│ ├── rparen_loc: ∅
23+
│ ├── operator_loc: (1,5)-(1,6) = "="
24+
│ └── value:
25+
│ @ RescueModifierNode (location: (1,7)-(1,24))
26+
│ ├── flags: ∅
27+
│ ├── expression:
28+
│ │ @ IntegerNode (location: (1,7)-(1,8))
29+
│ │ ├── flags: static_literal, decimal
30+
│ │ └── value: 1
31+
│ ├── keyword_loc: (1,9)-(1,15) = "rescue"
32+
│ └── rescue_expression:
33+
│ @ MultiWriteNode (location: (1,16)-(1,24))
34+
│ ├── flags: ∅
35+
│ ├── lefts: (length: 2)
36+
│ │ ├── @ LocalVariableTargetNode (location: (1,16)-(1,17))
37+
│ │ │ ├── flags: ∅
38+
│ │ │ ├── name: :a
39+
│ │ │ └── depth: 0
40+
│ │ └── @ LocalVariableTargetNode (location: (1,19)-(1,20))
41+
│ │ ├── flags: ∅
42+
│ │ ├── name: :b
43+
│ │ └── depth: 0
44+
│ ├── rest: ∅
45+
│ ├── rights: (length: 0)
46+
│ ├── lparen_loc: ∅
47+
│ ├── rparen_loc: ∅
48+
│ ├── operator_loc: (1,21)-(1,22) = "="
49+
│ └── value:
50+
│ @ IntegerNode (location: (1,23)-(1,24))
51+
│ ├── flags: static_literal, decimal
52+
│ └── value: 1
53+
├── @ MultiWriteNode (location: (2,0)-(2,24))
54+
│ ├── flags: newline
55+
│ ├── lefts: (length: 2)
56+
│ │ ├── @ LocalVariableTargetNode (location: (2,0)-(2,1))
57+
│ │ │ ├── flags: ∅
58+
│ │ │ ├── name: :x
59+
│ │ │ └── depth: 0
60+
│ │ └── @ LocalVariableTargetNode (location: (2,3)-(2,4))
61+
│ │ ├── flags: ∅
62+
│ │ ├── name: :y
63+
│ │ └── depth: 0
64+
│ ├── rest: ∅
65+
│ ├── rights: (length: 0)
66+
│ ├── lparen_loc: ∅
67+
│ ├── rparen_loc: ∅
68+
│ ├── operator_loc: (2,5)-(2,6) = "="
69+
│ └── value:
70+
│ @ RescueModifierNode (location: (2,7)-(2,24))
71+
│ ├── flags: ∅
72+
│ ├── expression:
73+
│ │ @ LocalVariableReadNode (location: (2,7)-(2,8))
74+
│ │ ├── flags: ∅
75+
│ │ ├── name: :a
76+
│ │ └── depth: 0
77+
│ ├── keyword_loc: (2,9)-(2,15) = "rescue"
78+
│ └── rescue_expression:
79+
│ @ MultiWriteNode (location: (2,16)-(2,24))
80+
│ ├── flags: ∅
81+
│ ├── lefts: (length: 2)
82+
│ │ ├── @ LocalVariableTargetNode (location: (2,16)-(2,17))
83+
│ │ │ ├── flags: ∅
84+
│ │ │ ├── name: :b
85+
│ │ │ └── depth: 0
86+
│ │ └── @ LocalVariableTargetNode (location: (2,19)-(2,20))
87+
│ │ ├── flags: ∅
88+
│ │ ├── name: :c
89+
│ │ └── depth: 0
90+
│ ├── rest: ∅
91+
│ ├── rights: (length: 0)
92+
│ ├── lparen_loc: ∅
93+
│ ├── rparen_loc: ∅
94+
│ ├── operator_loc: (2,21)-(2,22) = "="
95+
│ └── value:
96+
│ @ IntegerNode (location: (2,23)-(2,24))
97+
│ ├── flags: static_literal, decimal
98+
│ └── value: 1
99+
└── @ MultiWriteNode (location: (3,0)-(3,23))
100+
├── flags: newline
101+
├── lefts: (length: 2)
102+
│ ├── @ LocalVariableTargetNode (location: (3,0)-(3,1))
103+
│ │ ├── flags: ∅
104+
│ │ ├── name: :x
105+
│ │ └── depth: 0
106+
│ └── @ LocalVariableTargetNode (location: (3,3)-(3,4))
107+
│ ├── flags: ∅
108+
│ ├── name: :y
109+
│ └── depth: 0
110+
├── rest: ∅
111+
├── rights: (length: 0)
112+
├── lparen_loc: ∅
113+
├── rparen_loc: ∅
114+
├── operator_loc: (3,5)-(3,6) = "="
115+
└── value:
116+
@ RescueModifierNode (location: (3,7)-(3,23))
117+
├── flags: ∅
118+
├── expression:
119+
│ @ LocalVariableReadNode (location: (3,7)-(3,8))
120+
│ ├── flags: ∅
121+
│ ├── name: :a
122+
│ └── depth: 0
123+
├── keyword_loc: (3,9)-(3,15) = "rescue"
124+
└── rescue_expression:
125+
@ LocalVariableWriteNode (location: (3,16)-(3,23))
126+
├── flags: ∅
127+
├── name: :b
128+
├── depth: 0
129+
├── name_loc: (3,16)-(3,17) = "b"
130+
├── value:
131+
│ @ CallNode (location: (3,20)-(3,23))
132+
│ ├── flags: ignore_visibility
133+
│ ├── receiver: ∅
134+
│ ├── call_operator_loc: ∅
135+
│ ├── name: :c
136+
│ ├── message_loc: (3,20)-(3,21) = "c"
137+
│ ├── opening_loc: ∅
138+
│ ├── arguments:
139+
│ │ @ ArgumentsNode (location: (3,22)-(3,23))
140+
│ │ ├── flags: ∅
141+
│ │ └── arguments: (length: 1)
142+
│ │ └── @ CallNode (location: (3,22)-(3,23))
143+
│ │ ├── flags: variable_call, ignore_visibility
144+
│ │ ├── receiver: ∅
145+
│ │ ├── call_operator_loc: ∅
146+
│ │ ├── name: :d
147+
│ │ ├── message_loc: (3,22)-(3,23) = "d"
148+
│ │ ├── opening_loc: ∅
149+
│ │ ├── arguments: ∅
150+
│ │ ├── closing_loc: ∅
151+
│ │ ├── equal_loc: ∅
152+
│ │ └── block: ∅
153+
│ ├── closing_loc: ∅
154+
│ ├── equal_loc: ∅
155+
│ └── block: ∅
156+
└── operator_loc: (3,18)-(3,19) = "="

0 commit comments

Comments
 (0)