Skip to content

Commit adf7412

Browse files
authored
Merge pull request #3702 from Earlopain/endless-method-in-block-args
Reject endless method as a block parameter default
2 parents 74ab72b + 475fa46 commit adf7412

File tree

7 files changed

+364
-2
lines changed

7 files changed

+364
-2
lines changed

config.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ errors:
280280
- UNEXPECTED_INDEX_KEYWORDS
281281
- UNEXPECTED_LABEL
282282
- UNEXPECTED_MULTI_WRITE
283+
- UNEXPECTED_PARAMETER_DEFAULT_VALUE
283284
- UNEXPECTED_RANGE_OPERATOR
284285
- UNEXPECTED_SAFE_NAVIGATION
285286
- UNEXPECTED_TOKEN_CLOSE_CONTEXT
@@ -356,6 +357,8 @@ tokens:
356357
comment: "a newline character outside of other tokens"
357358
- name: PARENTHESIS_RIGHT
358359
comment: ")"
360+
- name: PIPE
361+
comment: "|"
359362
- name: SEMICOLON
360363
comment: ";"
361364
# Tokens from here on are not used for lookup, and can be in any order.
@@ -589,8 +592,6 @@ tokens:
589592
comment: "%I"
590593
- name: PERCENT_UPPER_W
591594
comment: "%W"
592-
- name: PIPE
593-
comment: "|"
594595
- name: PIPE_EQUAL
595596
comment: "|="
596597
- name: PIPE_PIPE

include/prism/parser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,9 @@ typedef enum {
299299
/** a rescue else statement within a do..end block */
300300
PM_CONTEXT_BLOCK_ELSE,
301301

302+
/** expressions in block parameters `foo do |...| end ` */
303+
PM_CONTEXT_BLOCK_PARAMETERS,
304+
302305
/** a rescue statement within a do..end block */
303306
PM_CONTEXT_BLOCK_RESCUE,
304307

snapshots/endless_method_as_default_arg.txt

Lines changed: 323 additions & 0 deletions
Large diffs are not rendered by default.

src/prism.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8606,6 +8606,7 @@ static const uint32_t context_terminators[] = {
86068606
[PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
86078607
[PM_CONTEXT_BLOCK_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
86088608
[PM_CONTEXT_BLOCK_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
8609+
[PM_CONTEXT_BLOCK_PARAMETERS] = (1U << PM_TOKEN_PIPE),
86098610
[PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
86108611
[PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
86118612
[PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
@@ -8756,6 +8757,7 @@ context_human(pm_context_t context) {
87568757
case PM_CONTEXT_BEGIN: return "begin statement";
87578758
case PM_CONTEXT_BLOCK_BRACES: return "'{'..'}' block";
87588759
case PM_CONTEXT_BLOCK_KEYWORDS: return "'do'..'end' block";
8760+
case PM_CONTEXT_BLOCK_PARAMETERS: return "'|'..'|' block parameter";
87598761
case PM_CONTEXT_CASE_WHEN: return "'when' clause";
87608762
case PM_CONTEXT_CASE_IN: return "'in' clause";
87618763
case PM_CONTEXT_CLASS: return "class definition";
@@ -15357,6 +15359,9 @@ parse_block_parameters(
1535715359
) {
1535815360
pm_parameters_node_t *parameters = NULL;
1535915361
if (!match1(parser, PM_TOKEN_SEMICOLON)) {
15362+
if (!is_lambda_literal) {
15363+
context_push(parser, PM_CONTEXT_BLOCK_PARAMETERS);
15364+
}
1536015365
parameters = parse_parameters(
1536115366
parser,
1536215367
is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
@@ -15367,6 +15372,9 @@ parse_block_parameters(
1536715372
true,
1536815373
(uint16_t) (depth + 1)
1536915374
);
15375+
if (!is_lambda_literal) {
15376+
context_pop(parser);
15377+
}
1537015378
}
1537115379

1537215380
pm_block_parameters_node_t *block_parameters = pm_block_parameters_node_create(parser, parameters, opening);
@@ -15722,6 +15730,7 @@ parse_return(pm_parser_t *parser, pm_node_t *node) {
1572215730
case PM_CONTEXT_BLOCK_ENSURE:
1572315731
case PM_CONTEXT_BLOCK_KEYWORDS:
1572415732
case PM_CONTEXT_BLOCK_RESCUE:
15733+
case PM_CONTEXT_BLOCK_PARAMETERS:
1572515734
case PM_CONTEXT_DEF_ELSE:
1572615735
case PM_CONTEXT_DEF_ENSURE:
1572715736
case PM_CONTEXT_DEF_PARAMS:
@@ -15758,6 +15767,7 @@ parse_block_exit(pm_parser_t *parser, pm_node_t *node) {
1575815767
case PM_CONTEXT_BLOCK_KEYWORDS:
1575915768
case PM_CONTEXT_BLOCK_ELSE:
1576015769
case PM_CONTEXT_BLOCK_ENSURE:
15770+
case PM_CONTEXT_BLOCK_PARAMETERS:
1576115771
case PM_CONTEXT_BLOCK_RESCUE:
1576215772
case PM_CONTEXT_DEFINED:
1576315773
case PM_CONTEXT_FOR:
@@ -17975,6 +17985,7 @@ parse_retry(pm_parser_t *parser, const pm_node_t *node) {
1797517985
case PM_CONTEXT_BEGIN:
1797617986
case PM_CONTEXT_BLOCK_BRACES:
1797717987
case PM_CONTEXT_BLOCK_KEYWORDS:
17988+
case PM_CONTEXT_BLOCK_PARAMETERS:
1797817989
case PM_CONTEXT_CASE_IN:
1797917990
case PM_CONTEXT_CASE_WHEN:
1798017991
case PM_CONTEXT_DEFAULT_PARAMS:
@@ -18055,6 +18066,7 @@ parse_yield(pm_parser_t *parser, const pm_node_t *node) {
1805518066
case PM_CONTEXT_BLOCK_KEYWORDS:
1805618067
case PM_CONTEXT_BLOCK_ELSE:
1805718068
case PM_CONTEXT_BLOCK_ENSURE:
18069+
case PM_CONTEXT_BLOCK_PARAMETERS:
1805818070
case PM_CONTEXT_BLOCK_RESCUE:
1805918071
case PM_CONTEXT_CASE_IN:
1806018072
case PM_CONTEXT_CASE_WHEN:
@@ -19618,6 +19630,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1961819630
if (!accept_endless_def) {
1961919631
pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
1962019632
}
19633+
if (
19634+
parser->current_context->context == PM_CONTEXT_DEFAULT_PARAMS &&
19635+
parser->current_context->prev->context == PM_CONTEXT_BLOCK_PARAMETERS
19636+
) {
19637+
PM_PARSER_ERR_FORMAT(parser, def_keyword.start, parser->previous.end, PM_ERR_UNEXPECTED_PARAMETER_DEFAULT_VALUE, "endless method definition");
19638+
}
1962119639
equal = parser->previous;
1962219640

1962319641
context_push(parser, PM_CONTEXT_DEF);

templates/src/diagnostic.c.erb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
361361
[PM_ERR_UNEXPECTED_INDEX_KEYWORDS] = { "unexpected keyword arg given in index assignment; keywords are not allowed in index assignment expressions", PM_ERROR_LEVEL_SYNTAX },
362362
[PM_ERR_UNEXPECTED_LABEL] = { "unexpected label", PM_ERROR_LEVEL_SYNTAX },
363363
[PM_ERR_UNEXPECTED_MULTI_WRITE] = { "unexpected multiple assignment; multiple assignment is not allowed in this context", PM_ERROR_LEVEL_SYNTAX },
364+
[PM_ERR_UNEXPECTED_PARAMETER_DEFAULT_VALUE] = { "unexpected %s; expected a default value for a parameter", PM_ERROR_LEVEL_SYNTAX },
364365
[PM_ERR_UNEXPECTED_RANGE_OPERATOR] = { "unexpected range operator; .. and ... are non-associative and cannot be chained", PM_ERROR_LEVEL_SYNTAX },
365366
[PM_ERR_UNEXPECTED_SAFE_NAVIGATION] = { "&. inside multiple assignment destination", PM_ERROR_LEVEL_SYNTAX },
366367
[PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT] = { "unexpected %s, assuming it is closing the parent %s", PM_ERROR_LEVEL_SYNTAX },
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
p do |a = def f = 1; b| end
2+
^~~~~~~ unexpected endless method definition; expected a default value for a parameter
3+
p do |a = def f = 1| 2; b|c end
4+
^~~~~~~ unexpected endless method definition; expected a default value for a parameter
5+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
def foo(a = def f = 1); end
2+
3+
def foo(a = def f = 1, b); end
4+
5+
def foo(b, a = def f = 1); end
6+
7+
def foo(a: def f = 1); end
8+
9+
def foo(a = def f = 1+2); end
10+
11+
->(a = def f = 1) {}

0 commit comments

Comments
 (0)