Skip to content

Commit d5bf5b1

Browse files
committed
Reject END { break } for Ruby 3.5
For [Bug #20409]
1 parent 5e0f47b commit d5bf5b1

File tree

7 files changed

+87
-2
lines changed

7 files changed

+87
-2
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
@ ProgramNode (location: (1,0)-(7,1))
2+
├── flags: ∅
3+
├── locals: []
4+
└── statements:
5+
@ StatementsNode (location: (1,0)-(7,1))
6+
├── flags: ∅
7+
└── body: (length: 2)
8+
├── @ PostExecutionNode (location: (1,0)-(3,1))
9+
│ ├── flags: newline
10+
│ ├── statements:
11+
│ │ @ StatementsNode (location: (2,2)-(2,8))
12+
│ │ ├── flags: ∅
13+
│ │ └── body: (length: 1)
14+
│ │ └── @ ReturnNode (location: (2,2)-(2,8))
15+
│ │ ├── flags: newline
16+
│ │ ├── keyword_loc: (2,2)-(2,8) = "return"
17+
│ │ └── arguments: ∅
18+
│ ├── keyword_loc: (1,0)-(1,3) = "END"
19+
│ ├── opening_loc: (1,4)-(1,5) = "{"
20+
│ └── closing_loc: (3,0)-(3,1) = "}"
21+
└── @ PostExecutionNode (location: (5,0)-(7,1))
22+
├── flags: newline
23+
├── statements:
24+
│ @ StatementsNode (location: (6,2)-(6,7))
25+
│ ├── flags: ∅
26+
│ └── body: (length: 1)
27+
│ └── @ BreakNode (location: (6,2)-(6,7))
28+
│ ├── flags: newline
29+
│ ├── arguments: ∅
30+
│ └── keyword_loc: (6,2)-(6,7) = "break"
31+
├── keyword_loc: (5,0)-(5,3) = "END"
32+
├── opening_loc: (5,4)-(5,5) = "{"
33+
└── closing_loc: (7,0)-(7,1) = "}"

snapshots/end_block_exit.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
@ ProgramNode (location: (1,0)-(3,1))
2+
├── flags: ∅
3+
├── locals: []
4+
└── statements:
5+
@ StatementsNode (location: (1,0)-(3,1))
6+
├── flags: ∅
7+
└── body: (length: 1)
8+
└── @ PostExecutionNode (location: (1,0)-(3,1))
9+
├── flags: newline
10+
├── statements:
11+
│ @ StatementsNode (location: (2,2)-(2,6))
12+
│ ├── flags: ∅
13+
│ └── body: (length: 1)
14+
│ └── @ NextNode (location: (2,2)-(2,6))
15+
│ ├── flags: newline
16+
│ ├── arguments: ∅
17+
│ └── keyword_loc: (2,2)-(2,6) = "next"
18+
├── keyword_loc: (1,0)-(1,3) = "END"
19+
├── opening_loc: (1,4)-(1,5) = "{"
20+
└── closing_loc: (3,0)-(3,1) = "}"

src/prism.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14950,12 +14950,22 @@ parse_block_exit(pm_parser_t *parser, pm_node_t *node) {
1495014950
case PM_CONTEXT_LAMBDA_ENSURE:
1495114951
case PM_CONTEXT_LAMBDA_RESCUE:
1495214952
case PM_CONTEXT_LOOP_PREDICATE:
14953-
case PM_CONTEXT_POSTEXE:
1495414953
case PM_CONTEXT_UNTIL:
1495514954
case PM_CONTEXT_WHILE:
1495614955
// These are the good cases. We're allowed to have a block exit
1495714956
// in these contexts.
1495814957
return;
14958+
case PM_CONTEXT_POSTEXE:
14959+
// https://bugs.ruby-lang.org/issues/20409
14960+
if (context_node->context == PM_CONTEXT_POSTEXE) {
14961+
if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_0) {
14962+
return;
14963+
}
14964+
if (PM_NODE_TYPE_P(node, PM_NEXT_NODE)) {
14965+
return;
14966+
}
14967+
}
14968+
PRISM_FALLTHROUGH
1495914969
case PM_CONTEXT_DEF:
1496014970
case PM_CONTEXT_DEF_PARAMS:
1496114971
case PM_CONTEXT_DEF_ELSE:
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
END {
2+
break
3+
^~~~~ Invalid break
4+
}
5+

test/prism/errors_test.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ class ErrorsTest < TestCase
99
base = File.expand_path("errors", __dir__)
1010
filepaths = Dir["**/*.txt", base: base]
1111

12+
PARSE_Y_EXCLUDES = [
13+
# https://bugs.ruby-lang.org/issues/20409
14+
"#{base}/4.0/end_block_exit.txt"
15+
]
16+
1217
filepaths.each do |filepath|
1318
ruby_versions_for(filepath).each do |version|
1419
define_method(:"test_#{version}_#{File.basename(filepath, ".txt")}") do
@@ -88,7 +93,9 @@ def assert_errors(filepath, version)
8893
expected = File.read(filepath, binmode: true, external_encoding: Encoding::UTF_8)
8994

9095
source = expected.lines.grep_v(/^\s*\^/).join.gsub(/\n*\z/, "")
91-
refute_valid_syntax(source) if CURRENT_MAJOR_MINOR == version
96+
if CURRENT_MAJOR_MINOR == version && !PARSE_Y_EXCLUDES.include?(filepath)
97+
refute_valid_syntax(source)
98+
end
9299

93100
result = Prism.parse(source, version: version)
94101
errors = result.errors
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
END {
2+
return
3+
}
4+
5+
END {
6+
break
7+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
END {
2+
next
3+
}

0 commit comments

Comments
 (0)