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
6 changes: 6 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,11 @@ flags:
- name: REPEATED_PARAMETER
comment: "a parameter name that has been repeated in the method signature"
comment: Flags for parameter nodes.
- name: ParenthesesNodeFlags
values:
- name: MULTIPLE_STATEMENTS
comment: "parentheses that contain multiple potentially void statements"
comment: Flags for parentheses nodes.
- name: RangeFlags
values:
- name: EXCLUDE_END
Expand Down Expand Up @@ -3851,6 +3856,7 @@ nodes:
^^^^^^^
end
- name: ParenthesesNode
flags: ParenthesesNodeFlags
fields:
- name: body
type: node?
Expand Down
44 changes: 34 additions & 10 deletions src/prism.c
Original file line number Diff line number Diff line change
Expand Up @@ -6406,12 +6406,13 @@ pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_st
* Allocate and initialize new ParenthesesNode node.
*/
static pm_parentheses_node_t *
pm_parentheses_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_node_t *body, const pm_token_t *closing) {
pm_parentheses_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_node_t *body, const pm_token_t *closing, pm_node_flags_t flags) {
pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);

*node = (pm_parentheses_node_t) {
{
.type = PM_PARENTHESES_NODE,
.flags = flags,
.node_id = PM_NODE_IDENTIFY(parser),
.location = {
.start = opening->start,
Expand Down Expand Up @@ -17551,7 +17552,7 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p
pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
accept1(parser, PM_TOKEN_NEWLINE);
expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
pm_node_t *right = (pm_node_t *) pm_parentheses_node_create(parser, &opening, body, &parser->previous);
pm_node_t *right = (pm_node_t *) pm_parentheses_node_create(parser, &opening, body, &parser->previous, 0);

if (node == NULL) {
node = right;
Expand Down Expand Up @@ -18174,12 +18175,19 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
case PM_TOKEN_PARENTHESIS_LEFT:
case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
pm_token_t opening = parser->current;
pm_node_flags_t flags = 0;

pm_node_list_t current_block_exits = { 0 };
pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);

parser_lex(parser);
while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
while (true) {
if (accept1(parser, PM_TOKEN_SEMICOLON)) {
flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
} else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
break;
}
}

// If this is the end of the file or we match a right parenthesis, then
// we have an empty parentheses node, and we can immediately return.
Expand All @@ -18189,7 +18197,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pop_block_exits(parser, previous_block_exits);
pm_node_list_free(&current_block_exits);

return (pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->previous);
return (pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->previous, flags);
}

// Otherwise, we're going to parse the first statement in the list
Expand All @@ -18202,9 +18210,23 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// Determine if this statement is followed by a terminator. In the
// case of a single statement, this is fine. But in the case of
// multiple statements it's required.
bool terminator_found = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
bool terminator_found = false;

if (accept1(parser, PM_TOKEN_SEMICOLON)) {
terminator_found = true;
flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
} else if (accept1(parser, PM_TOKEN_NEWLINE)) {
terminator_found = true;
}

if (terminator_found) {
while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
while (true) {
if (accept1(parser, PM_TOKEN_SEMICOLON)) {
flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
} else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
break;
}
}
}

// If we hit a right parenthesis, then we're done parsing the
Expand Down Expand Up @@ -18276,13 +18298,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_statements_node_t *statements = pm_statements_node_create(parser);
pm_statements_node_body_append(parser, statements, statement, true);

return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous);
return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous, flags);
}

// If we have more than one statement in the set of parentheses,
// then we are going to parse all of them as a list of statements.
// We'll do that here.
context_push(parser, PM_CONTEXT_PARENS);
flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;

pm_statements_node_t *statements = pm_statements_node_create(parser);
pm_statements_node_body_append(parser, statements, statement, true);

Expand Down Expand Up @@ -18359,7 +18383,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_node_list_free(&current_block_exits);

pm_void_statements_check(parser, statements, true);
return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous);
return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous, flags);
}
case PM_TOKEN_BRACE_LEFT: {
// If we were passed a current_hash_keys via the parser, then that
Expand Down Expand Up @@ -19405,7 +19429,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);

operator = parser->previous;
receiver = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen);
receiver = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0);

// To push `PM_CONTEXT_DEF_PARAMS` again is for the same
// reason as described the above.
Expand Down Expand Up @@ -19738,7 +19762,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_token_t lparen = parser->previous;

if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
receiver = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous);
receiver = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0);
} else {
arguments.opening_loc = PM_LOCATION_TOKEN_VALUE(&lparen);
receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
Expand Down
2 changes: 1 addition & 1 deletion test/prism/snapshots/break.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion test/prism/snapshots/methods.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion test/prism/snapshots/next.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion test/prism/snapshots/nils.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion test/prism/snapshots/return.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion test/prism/snapshots/unparser/corpus/literal/def.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion test/prism/snapshots/unparser/corpus/literal/send.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion test/prism/snapshots/variables.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion test/prism/snapshots/whitequark/cond_begin_masgn.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions test/prism/snapshots/whitequark/ruby_bug_19281.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading