Skip to content

Commit 26cfb91

Browse files
committed
Pop block stack before finishing command call arguments within parenthesized call
1 parent 7c415b1 commit 26cfb91

2 files changed

Lines changed: 39 additions & 3 deletions

File tree

src/prism.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19055,8 +19055,11 @@ parse_parentheses(pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t
1905519055
lex_state_set(parser, PM_LEX_STATE_ENDARG);
1905619056
}
1905719057

19058-
parser_lex(parser);
19058+
/* Pop before consuming the closing `)` so the following token (e.g. a
19059+
* `do`) is lexed in the enclosing context rather than as a block
19060+
* belonging to the parenthesized expression. */
1905919061
pm_accepts_block_stack_pop(parser);
19062+
parser_lex(parser);
1906019063
pop_block_exits(parser, previous_block_exits);
1906119064

1906219065
if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
@@ -19327,14 +19330,20 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u
1932719330

1932819331
accept1(parser, PM_TOKEN_NEWLINE);
1932919332

19333+
/* Pop before consuming the closing `]` so the following token (e.g.
19334+
* a `do`) is lexed in the enclosing context rather than as a block
19335+
* belonging to the array's interior. Otherwise a `do` block would
19336+
* wrongly bind to a command with an array argument, as in
19337+
* `foo(m [] do end)`. */
19338+
pm_accepts_block_stack_pop(parser);
19339+
1933019340
if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
1933119341
PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
1933219342
parser->previous.start = parser->previous.end;
1933319343
parser->previous.type = 0;
1933419344
}
1933519345

1933619346
pm_array_node_close_set(parser, array, &parser->previous);
19337-
pm_accepts_block_stack_pop(parser);
1933819347

1933919348
return UP(array);
1934019349
}
@@ -20653,6 +20662,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u
2065320662
}
2065420663

2065520664
parser_warn_indentation_mismatch(parser, opening_newline_index, &operator, false, false);
20665+
20666+
/* Pop before consuming the closing `}` so the following token
20667+
* (e.g. a `do`) is lexed in the enclosing context rather than
20668+
* as a block belonging to the lambda's interior. */
20669+
pm_accepts_block_stack_pop(parser);
2065620670
expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening);
2065720671
} else {
2065820672
expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
@@ -20669,6 +20683,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u
2066920683
parser_warn_indentation_mismatch(parser, opening_newline_index, &operator, false, false);
2067020684
}
2067120685

20686+
/* As with the brace case above, pop before consuming `end`. */
20687+
pm_accepts_block_stack_pop(parser);
2067220688
expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &operator);
2067320689
}
2067420690

@@ -20677,7 +20693,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u
2067720693
pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &operator, &parser->previous);
2067820694

2067920695
pm_parser_scope_pop(parser);
20680-
pm_accepts_block_stack_pop(parser);
2068120696

2068220697
return UP(pm_lambda_node_create(parser, &locals, &operator, &opening, &parser->previous, parameters, body));
2068320698
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
foo(m [] do end)
2+
^~ unexpected 'do'; expected a `)` to close the arguments
3+
^~ unexpected 'do', expecting end-of-input
4+
^~ unexpected 'do', ignoring it
5+
^~~ unexpected 'end', ignoring it
6+
^ unexpected ')', ignoring it
7+
8+
foo(m -> {} do end)
9+
^~ unexpected 'do'; expected a `)` to close the arguments
10+
^~ unexpected 'do', expecting end-of-input
11+
^~ unexpected 'do', ignoring it
12+
^~~ unexpected 'end', ignoring it
13+
^ unexpected ')', ignoring it
14+
15+
foo(m (1) do end)
16+
^~ unexpected 'do'; expected a `)` to close the arguments
17+
^~ unexpected 'do', expecting end-of-input
18+
^~ unexpected 'do', ignoring it
19+
^~~ unexpected 'end', ignoring it
20+
^ unexpected ')', ignoring it
21+

0 commit comments

Comments
 (0)