Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ errors:
- UNEXPECTED_INDEX_KEYWORDS
- UNEXPECTED_LABEL
- UNEXPECTED_MULTI_WRITE
- UNEXPECTED_PARAMETER_DEFAULT_VALUE
- UNEXPECTED_RANGE_OPERATOR
- UNEXPECTED_SAFE_NAVIGATION
- UNEXPECTED_TOKEN_CLOSE_CONTEXT
Expand Down Expand Up @@ -356,6 +357,8 @@ tokens:
comment: "a newline character outside of other tokens"
- name: PARENTHESIS_RIGHT
comment: ")"
- name: PIPE
comment: "|"
- name: SEMICOLON
comment: ";"
# Tokens from here on are not used for lookup, and can be in any order.
Expand Down Expand Up @@ -589,8 +592,6 @@ tokens:
comment: "%I"
- name: PERCENT_UPPER_W
comment: "%W"
- name: PIPE
comment: "|"
- name: PIPE_EQUAL
comment: "|="
- name: PIPE_PIPE
Expand Down
3 changes: 3 additions & 0 deletions include/prism/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,9 @@ typedef enum {
/** a rescue else statement within a do..end block */
PM_CONTEXT_BLOCK_ELSE,

/** expressions in block parameters `foo do |...| end ` */
PM_CONTEXT_BLOCK_PARAMETERS,

/** a rescue statement within a do..end block */
PM_CONTEXT_BLOCK_RESCUE,

Expand Down
323 changes: 323 additions & 0 deletions snapshots/endless_method_as_default_arg.txt

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions src/prism.c
Original file line number Diff line number Diff line change
Expand Up @@ -8606,6 +8606,7 @@ static const uint32_t context_terminators[] = {
[PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
[PM_CONTEXT_BLOCK_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
[PM_CONTEXT_BLOCK_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
[PM_CONTEXT_BLOCK_PARAMETERS] = (1U << PM_TOKEN_PIPE),
[PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
[PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
[PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
Expand Down Expand Up @@ -8756,6 +8757,7 @@ context_human(pm_context_t context) {
case PM_CONTEXT_BEGIN: return "begin statement";
case PM_CONTEXT_BLOCK_BRACES: return "'{'..'}' block";
case PM_CONTEXT_BLOCK_KEYWORDS: return "'do'..'end' block";
case PM_CONTEXT_BLOCK_PARAMETERS: return "'|'..'|' block parameter";
case PM_CONTEXT_CASE_WHEN: return "'when' clause";
case PM_CONTEXT_CASE_IN: return "'in' clause";
case PM_CONTEXT_CLASS: return "class definition";
Expand Down Expand Up @@ -15357,6 +15359,9 @@ parse_block_parameters(
) {
pm_parameters_node_t *parameters = NULL;
if (!match1(parser, PM_TOKEN_SEMICOLON)) {
if (!is_lambda_literal) {
context_push(parser, PM_CONTEXT_BLOCK_PARAMETERS);
}
parameters = parse_parameters(
parser,
is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
Expand All @@ -15367,6 +15372,9 @@ parse_block_parameters(
true,
(uint16_t) (depth + 1)
);
if (!is_lambda_literal) {
context_pop(parser);
}
}

pm_block_parameters_node_t *block_parameters = pm_block_parameters_node_create(parser, parameters, opening);
Expand Down Expand Up @@ -15722,6 +15730,7 @@ parse_return(pm_parser_t *parser, pm_node_t *node) {
case PM_CONTEXT_BLOCK_ENSURE:
case PM_CONTEXT_BLOCK_KEYWORDS:
case PM_CONTEXT_BLOCK_RESCUE:
case PM_CONTEXT_BLOCK_PARAMETERS:
case PM_CONTEXT_DEF_ELSE:
case PM_CONTEXT_DEF_ENSURE:
case PM_CONTEXT_DEF_PARAMS:
Expand Down Expand Up @@ -15758,6 +15767,7 @@ parse_block_exit(pm_parser_t *parser, pm_node_t *node) {
case PM_CONTEXT_BLOCK_KEYWORDS:
case PM_CONTEXT_BLOCK_ELSE:
case PM_CONTEXT_BLOCK_ENSURE:
case PM_CONTEXT_BLOCK_PARAMETERS:
case PM_CONTEXT_BLOCK_RESCUE:
case PM_CONTEXT_DEFINED:
case PM_CONTEXT_FOR:
Expand Down Expand Up @@ -17975,6 +17985,7 @@ parse_retry(pm_parser_t *parser, const pm_node_t *node) {
case PM_CONTEXT_BEGIN:
case PM_CONTEXT_BLOCK_BRACES:
case PM_CONTEXT_BLOCK_KEYWORDS:
case PM_CONTEXT_BLOCK_PARAMETERS:
case PM_CONTEXT_CASE_IN:
case PM_CONTEXT_CASE_WHEN:
case PM_CONTEXT_DEFAULT_PARAMS:
Expand Down Expand Up @@ -18055,6 +18066,7 @@ parse_yield(pm_parser_t *parser, const pm_node_t *node) {
case PM_CONTEXT_BLOCK_KEYWORDS:
case PM_CONTEXT_BLOCK_ELSE:
case PM_CONTEXT_BLOCK_ENSURE:
case PM_CONTEXT_BLOCK_PARAMETERS:
case PM_CONTEXT_BLOCK_RESCUE:
case PM_CONTEXT_CASE_IN:
case PM_CONTEXT_CASE_WHEN:
Expand Down Expand Up @@ -19618,6 +19630,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
if (!accept_endless_def) {
pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
}
if (
parser->current_context->context == PM_CONTEXT_DEFAULT_PARAMS &&
parser->current_context->prev->context == PM_CONTEXT_BLOCK_PARAMETERS
) {
PM_PARSER_ERR_FORMAT(parser, def_keyword.start, parser->previous.end, PM_ERR_UNEXPECTED_PARAMETER_DEFAULT_VALUE, "endless method definition");
}
equal = parser->previous;

context_push(parser, PM_CONTEXT_DEF);
Expand Down
1 change: 1 addition & 0 deletions templates/src/diagnostic.c.erb
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_UNEXPECTED_INDEX_KEYWORDS] = { "unexpected keyword arg given in index assignment; keywords are not allowed in index assignment expressions", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_LABEL] = { "unexpected label", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_MULTI_WRITE] = { "unexpected multiple assignment; multiple assignment is not allowed in this context", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_PARAMETER_DEFAULT_VALUE] = { "unexpected %s; expected a default value for a parameter", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_RANGE_OPERATOR] = { "unexpected range operator; .. and ... are non-associative and cannot be chained", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_SAFE_NAVIGATION] = { "&. inside multiple assignment destination", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT] = { "unexpected %s, assuming it is closing the parent %s", PM_ERROR_LEVEL_SYNTAX },
Expand Down
5 changes: 5 additions & 0 deletions test/prism/errors/block_args_with_endless_def.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
p do |a = def f = 1; b| end
^~~~~~~ unexpected endless method definition; expected a default value for a parameter
p do |a = def f = 1| 2; b|c end
^~~~~~~ unexpected endless method definition; expected a default value for a parameter

11 changes: 11 additions & 0 deletions test/prism/fixtures/endless_method_as_default_arg.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
def foo(a = def f = 1); end

def foo(a = def f = 1, b); end

def foo(b, a = def f = 1); end

def foo(a: def f = 1); end

def foo(a = def f = 1+2); end

->(a = def f = 1) {}
Loading