Skip to content

Commit fcf06b0

Browse files
authored
Merge pull request #3630 from Earlopain/command-call-return-args
Reject some cases with `return` and command calls
2 parents 603d651 + 3a38b19 commit fcf06b0

File tree

9 files changed

+367
-98
lines changed

9 files changed

+367
-98
lines changed

lib/prism/translation/parser/lexer.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ class Lexer
203203
# The following token types are listed as those classified as `tLPAREN`.
204204
LPAREN_CONVERSION_TOKEN_TYPES = Set.new([
205205
:kBREAK, :tCARET, :kCASE, :tDIVIDE, :kFOR, :kIF, :kNEXT, :kRETURN, :kUNTIL, :kWHILE, :tAMPER, :tANDOP, :tBANG, :tCOMMA, :tDOT2, :tDOT3,
206-
:tEQL, :tLPAREN, :tLPAREN2, :tLPAREN_ARG, :tLSHFT, :tNL, :tOP_ASGN, :tOROP, :tPIPE, :tSEMI, :tSTRING_DBEG, :tUMINUS, :tUPLUS
206+
:tEQL, :tLPAREN, :tLPAREN2, :tLPAREN_ARG, :tLSHFT, :tNL, :tOP_ASGN, :tOROP, :tPIPE, :tSEMI, :tSTRING_DBEG, :tUMINUS, :tUPLUS, :tLCURLY
207207
])
208208

209209
# Types of tokens that are allowed to continue a method call with comments in-between.

snapshots/break.txt

Lines changed: 143 additions & 52 deletions
Large diffs are not rendered by default.

snapshots/next.txt

Lines changed: 116 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
@ ProgramNode (location: (1,0)-(24,15))
1+
@ ProgramNode (location: (1,0)-(28,23))
22
├── flags: ∅
33
├── locals: []
44
└── statements:
5-
@ StatementsNode (location: (1,0)-(24,15))
5+
@ StatementsNode (location: (1,0)-(28,23))
66
├── flags: ∅
7-
└── body: (length: 10)
7+
└── body: (length: 12)
88
├── @ CallNode (location: (1,0)-(1,12))
99
│ ├── flags: newline, ignore_visibility
1010
│ ├── receiver: ∅
@@ -332,41 +332,132 @@
332332
│ │ └── keyword_loc: (22,6)-(22,10) = "next"
333333
│ ├── opening_loc: (22,4)-(22,5) = "{"
334334
│ └── closing_loc: (22,13)-(22,14) = "}"
335-
└── @ CallNode (location: (24,0)-(24,15))
335+
├── @ CallNode (location: (24,0)-(24,15))
336+
│ ├── flags: newline, ignore_visibility
337+
│ ├── receiver: ∅
338+
│ ├── call_operator_loc: ∅
339+
│ ├── name: :tap
340+
│ ├── message_loc: (24,0)-(24,3) = "tap"
341+
│ ├── opening_loc: ∅
342+
│ ├── arguments: ∅
343+
│ ├── closing_loc: ∅
344+
│ └── block:
345+
│ @ BlockNode (location: (24,4)-(24,15))
346+
│ ├── flags: ∅
347+
│ ├── locals: []
348+
│ ├── parameters: ∅
349+
│ ├── body:
350+
│ │ @ StatementsNode (location: (24,6)-(24,13))
351+
│ │ ├── flags: ∅
352+
│ │ └── body: (length: 1)
353+
│ │ └── @ NextNode (location: (24,6)-(24,13))
354+
│ │ ├── flags: newline
355+
│ │ ├── arguments:
356+
│ │ │ @ ArgumentsNode (location: (24,10)-(24,13))
357+
│ │ │ ├── flags: ∅
358+
│ │ │ └── arguments: (length: 1)
359+
│ │ │ └── @ ParenthesesNode (location: (24,10)-(24,13))
360+
│ │ │ ├── flags: ∅
361+
│ │ │ ├── body:
362+
│ │ │ │ @ StatementsNode (location: (24,11)-(24,12))
363+
│ │ │ │ ├── flags: ∅
364+
│ │ │ │ └── body: (length: 1)
365+
│ │ │ │ └── @ IntegerNode (location: (24,11)-(24,12))
366+
│ │ │ │ ├── flags: newline, static_literal, decimal
367+
│ │ │ │ └── value: 1
368+
│ │ │ ├── opening_loc: (24,10)-(24,11) = "("
369+
│ │ │ └── closing_loc: (24,12)-(24,13) = ")"
370+
│ │ └── keyword_loc: (24,6)-(24,10) = "next"
371+
│ ├── opening_loc: (24,4)-(24,5) = "{"
372+
│ └── closing_loc: (24,14)-(24,15) = "}"
373+
├── @ CallNode (location: (26,0)-(26,16))
374+
│ ├── flags: newline, ignore_visibility
375+
│ ├── receiver: ∅
376+
│ ├── call_operator_loc: ∅
377+
│ ├── name: :tap
378+
│ ├── message_loc: (26,0)-(26,3) = "tap"
379+
│ ├── opening_loc: ∅
380+
│ ├── arguments: ∅
381+
│ ├── closing_loc: ∅
382+
│ └── block:
383+
│ @ BlockNode (location: (26,4)-(26,16))
384+
│ ├── flags: ∅
385+
│ ├── locals: []
386+
│ ├── parameters: ∅
387+
│ ├── body:
388+
│ │ @ StatementsNode (location: (26,6)-(26,14))
389+
│ │ ├── flags: ∅
390+
│ │ └── body: (length: 1)
391+
│ │ └── @ ParenthesesNode (location: (26,6)-(26,14))
392+
│ │ ├── flags: newline
393+
│ │ ├── body:
394+
│ │ │ @ StatementsNode (location: (26,7)-(26,13))
395+
│ │ │ ├── flags: ∅
396+
│ │ │ └── body: (length: 1)
397+
│ │ │ └── @ NextNode (location: (26,7)-(26,13))
398+
│ │ │ ├── flags: newline
399+
│ │ │ ├── arguments:
400+
│ │ │ │ @ ArgumentsNode (location: (26,12)-(26,13))
401+
│ │ │ │ ├── flags: ∅
402+
│ │ │ │ └── arguments: (length: 1)
403+
│ │ │ │ └── @ IntegerNode (location: (26,12)-(26,13))
404+
│ │ │ │ ├── flags: static_literal, decimal
405+
│ │ │ │ └── value: 1
406+
│ │ │ └── keyword_loc: (26,7)-(26,11) = "next"
407+
│ │ ├── opening_loc: (26,6)-(26,7) = "("
408+
│ │ └── closing_loc: (26,13)-(26,14) = ")"
409+
│ ├── opening_loc: (26,4)-(26,5) = "{"
410+
│ └── closing_loc: (26,15)-(26,16) = "}"
411+
└── @ CallNode (location: (28,0)-(28,23))
336412
├── flags: newline, ignore_visibility
337413
├── receiver: ∅
338414
├── call_operator_loc: ∅
339415
├── name: :tap
340-
├── message_loc: (24,0)-(24,3) = "tap"
416+
├── message_loc: (28,0)-(28,3) = "tap"
341417
├── opening_loc: ∅
342418
├── arguments: ∅
343419
├── closing_loc: ∅
344420
└── block:
345-
@ BlockNode (location: (24,4)-(24,15))
421+
@ BlockNode (location: (28,4)-(28,23))
346422
├── flags: ∅
347423
├── locals: []
348424
├── parameters: ∅
349425
├── body:
350-
│ @ StatementsNode (location: (24,6)-(24,13))
426+
│ @ StatementsNode (location: (28,6)-(28,21))
351427
│ ├── flags: ∅
352428
│ └── body: (length: 1)
353-
│ └── @ NextNode (location: (24,6)-(24,13))
429+
│ └── @ AndNode (location: (28,6)-(28,21))
354430
│ ├── flags: newline
355-
│ ├── arguments:
356-
│ │ @ ArgumentsNode (location: (24,10)-(24,13))
431+
│ ├── left:
432+
│ │ @ CallNode (location: (28,6)-(28,9))
433+
│ │ ├── flags: variable_call, ignore_visibility
434+
│ │ ├── receiver: ∅
435+
│ │ ├── call_operator_loc: ∅
436+
│ │ ├── name: :foo
437+
│ │ ├── message_loc: (28,6)-(28,9) = "foo"
438+
│ │ ├── opening_loc: ∅
439+
│ │ ├── arguments: ∅
440+
│ │ ├── closing_loc: ∅
441+
│ │ └── block: ∅
442+
│ ├── right:
443+
│ │ @ ParenthesesNode (location: (28,13)-(28,21))
357444
│ │ ├── flags: ∅
358-
│ │ └── arguments: (length: 1)
359-
│ │ └── @ ParenthesesNode (location: (24,10)-(24,13))
360-
│ │ ├── flags: ∅
361-
│ │ ├── body:
362-
│ │ │ @ StatementsNode (location: (24,11)-(24,12))
363-
│ │ │ ├── flags: ∅
364-
│ │ │ └── body: (length: 1)
365-
│ │ │ └── @ IntegerNode (location: (24,11)-(24,12))
366-
│ │ │ ├── flags: newline, static_literal, decimal
367-
│ │ │ └── value: 1
368-
│ │ ├── opening_loc: (24,10)-(24,11) = "("
369-
│ │ └── closing_loc: (24,12)-(24,13) = ")"
370-
│ └── keyword_loc: (24,6)-(24,10) = "next"
371-
├── opening_loc: (24,4)-(24,5) = "{"
372-
└── closing_loc: (24,14)-(24,15) = "}"
445+
│ │ ├── body:
446+
│ │ │ @ StatementsNode (location: (28,14)-(28,20))
447+
│ │ │ ├── flags: ∅
448+
│ │ │ └── body: (length: 1)
449+
│ │ │ └── @ NextNode (location: (28,14)-(28,20))
450+
│ │ │ ├── flags: newline
451+
│ │ │ ├── arguments:
452+
│ │ │ │ @ ArgumentsNode (location: (28,19)-(28,20))
453+
│ │ │ │ ├── flags: ∅
454+
│ │ │ │ └── arguments: (length: 1)
455+
│ │ │ │ └── @ IntegerNode (location: (28,19)-(28,20))
456+
│ │ │ │ ├── flags: static_literal, decimal
457+
│ │ │ │ └── value: 1
458+
│ │ │ └── keyword_loc: (28,14)-(28,18) = "next"
459+
│ │ ├── opening_loc: (28,13)-(28,14) = "("
460+
│ │ └── closing_loc: (28,20)-(28,21) = ")"
461+
│ └── operator_loc: (28,10)-(28,12) = "&&"
462+
├── opening_loc: (28,4)-(28,5) = "{"
463+
└── closing_loc: (28,22)-(28,23) = "}"

snapshots/return.txt

Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
@ ProgramNode (location: (1,0)-(23,9))
1+
@ ProgramNode (location: (1,0)-(27,17))
22
├── flags: ∅
33
├── locals: []
44
└── statements:
5-
@ StatementsNode (location: (1,0)-(23,9))
5+
@ StatementsNode (location: (1,0)-(27,17))
66
├── flags: ∅
7-
└── body: (length: 10)
7+
└── body: (length: 12)
88
├── @ ReturnNode (location: (1,0)-(1,6))
99
│ ├── flags: newline
1010
│ ├── keyword_loc: (1,0)-(1,6) = "return"
@@ -159,21 +159,72 @@
159159
│ ├── body: ∅
160160
│ ├── opening_loc: (21,6)-(21,7) = "("
161161
│ └── closing_loc: (21,7)-(21,8) = ")"
162-
└── @ ReturnNode (location: (23,0)-(23,9))
162+
├── @ ReturnNode (location: (23,0)-(23,9))
163+
│ ├── flags: newline
164+
│ ├── keyword_loc: (23,0)-(23,6) = "return"
165+
│ └── arguments:
166+
│ @ ArgumentsNode (location: (23,6)-(23,9))
167+
│ ├── flags: ∅
168+
│ └── arguments: (length: 1)
169+
│ └── @ ParenthesesNode (location: (23,6)-(23,9))
170+
│ ├── flags: ∅
171+
│ ├── body:
172+
│ │ @ StatementsNode (location: (23,7)-(23,8))
173+
│ │ ├── flags: ∅
174+
│ │ └── body: (length: 1)
175+
│ │ └── @ IntegerNode (location: (23,7)-(23,8))
176+
│ │ ├── flags: newline, static_literal, decimal
177+
│ │ └── value: 1
178+
│ ├── opening_loc: (23,6)-(23,7) = "("
179+
│ └── closing_loc: (23,8)-(23,9) = ")"
180+
├── @ ParenthesesNode (location: (25,0)-(25,10))
181+
│ ├── flags: newline
182+
│ ├── body:
183+
│ │ @ StatementsNode (location: (25,1)-(25,9))
184+
│ │ ├── flags: ∅
185+
│ │ └── body: (length: 1)
186+
│ │ └── @ ReturnNode (location: (25,1)-(25,9))
187+
│ │ ├── flags: newline
188+
│ │ ├── keyword_loc: (25,1)-(25,7) = "return"
189+
│ │ └── arguments:
190+
│ │ @ ArgumentsNode (location: (25,8)-(25,9))
191+
│ │ ├── flags: ∅
192+
│ │ └── arguments: (length: 1)
193+
│ │ └── @ IntegerNode (location: (25,8)-(25,9))
194+
│ │ ├── flags: static_literal, decimal
195+
│ │ └── value: 1
196+
│ ├── opening_loc: (25,0)-(25,1) = "("
197+
│ └── closing_loc: (25,9)-(25,10) = ")"
198+
└── @ AndNode (location: (27,0)-(27,17))
163199
├── flags: newline
164-
├── keyword_loc: (23,0)-(23,6) = "return"
165-
└── arguments:
166-
@ ArgumentsNode (location: (23,6)-(23,9))
167-
├── flags: ∅
168-
└── arguments: (length: 1)
169-
└── @ ParenthesesNode (location: (23,6)-(23,9))
170-
├── flags: ∅
171-
├── body:
172-
│ @ StatementsNode (location: (23,7)-(23,8))
173-
│ ├── flags: ∅
174-
│ └── body: (length: 1)
175-
│ └── @ IntegerNode (location: (23,7)-(23,8))
176-
│ ├── flags: newline, static_literal, decimal
177-
│ └── value: 1
178-
├── opening_loc: (23,6)-(23,7) = "("
179-
└── closing_loc: (23,8)-(23,9) = ")"
200+
├── left:
201+
│ @ CallNode (location: (27,0)-(27,3))
202+
│ ├── flags: variable_call, ignore_visibility
203+
│ ├── receiver: ∅
204+
│ ├── call_operator_loc: ∅
205+
│ ├── name: :foo
206+
│ ├── message_loc: (27,0)-(27,3) = "foo"
207+
│ ├── opening_loc: ∅
208+
│ ├── arguments: ∅
209+
│ ├── closing_loc: ∅
210+
│ └── block: ∅
211+
├── right:
212+
│ @ ParenthesesNode (location: (27,7)-(27,17))
213+
│ ├── flags: ∅
214+
│ ├── body:
215+
│ │ @ StatementsNode (location: (27,8)-(27,16))
216+
│ │ ├── flags: ∅
217+
│ │ └── body: (length: 1)
218+
│ │ └── @ ReturnNode (location: (27,8)-(27,16))
219+
│ │ ├── flags: newline
220+
│ │ ├── keyword_loc: (27,8)-(27,14) = "return"
221+
│ │ └── arguments:
222+
│ │ @ ArgumentsNode (location: (27,15)-(27,16))
223+
│ │ ├── flags: ∅
224+
│ │ └── arguments: (length: 1)
225+
│ │ └── @ IntegerNode (location: (27,15)-(27,16))
226+
│ │ ├── flags: static_literal, decimal
227+
│ │ └── value: 1
228+
│ ├── opening_loc: (27,7)-(27,8) = "("
229+
│ └── closing_loc: (27,16)-(27,17) = ")"
230+
└── operator_loc: (27,4)-(27,6) = "&&"

src/prism.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19102,7 +19102,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1910219102
pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].left;
1910319103

1910419104
if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
19105+
pm_token_t next = parser->current;
1910519106
parse_arguments(parser, &arguments, false, PM_TOKEN_EOF, (uint16_t) (depth + 1));
19107+
19108+
// Reject `foo && return bar`.
19109+
if (!accepts_command_call && arguments.arguments != NULL) {
19110+
PM_PARSER_ERR_TOKEN_FORMAT(parser, next, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(next.type));
19111+
}
1910619112
}
1910719113
}
1910819114

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
foo && return bar
2+
^~~ unexpected local variable or method, expecting end-of-input
3+
4+
tap { foo && break bar }
5+
^~~ unexpected local variable or method, expecting end-of-input
6+
7+
tap { foo && next bar }
8+
^~~ unexpected local variable or method, expecting end-of-input
9+
10+
foo && return()
11+
^ unexpected '(', expecting end-of-input
12+
13+
foo && return(bar)
14+
^ unexpected '(', expecting end-of-input
15+
16+
foo && return(bar, baz)
17+
^~~~~~~~~~ unexpected write target
18+
^ unexpected '(', expecting end-of-input
19+

test/prism/fixtures/break.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ tap { break() }
2020

2121
tap { break(1) }
2222

23+
tap { (break 1) }
24+
25+
tap { foo && (break 1) }
26+
2327
foo { break 42 } == 42
2428

2529
foo { |a| break } == 42

test/prism/fixtures/next.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,7 @@ tap { next
2222
tap { next() }
2323

2424
tap { next(1) }
25+
26+
tap { (next 1) }
27+
28+
tap { foo && (next 1) }

test/prism/fixtures/return.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@ return()
2222

2323
return(1)
2424

25+
(return 1)
26+
27+
foo && (return 1)

0 commit comments

Comments
 (0)