Skip to content

Commit 591f116

Browse files
committed
Reverse sync from upstream
1 parent 63084bd commit 591f116

File tree

4 files changed

+48
-27
lines changed

4 files changed

+48
-27
lines changed

config.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,10 @@ errors:
217217
- PARAMETER_UNEXPECTED_FWD
218218
- PARAMETER_UNEXPECTED_NO_KW
219219
- PARAMETER_WILD_LOOSE_COMMA
220+
- PATTERN_ALTERNATIVE_AFTER_CAPTURE
220221
- PATTERN_ARRAY_MULTIPLE_RESTS
221222
- PATTERN_CAPTURE_DUPLICATE
223+
- PATTERN_CAPTURE_IN_ALTERNATIVE
222224
- PATTERN_EXPRESSION_AFTER_BRACKET
223225
- PATTERN_EXPRESSION_AFTER_COMMA
224226
- PATTERN_EXPRESSION_AFTER_HROCKET

src/prism.c

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16947,6 +16947,11 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
1694716947
#define PM_PARSE_PATTERN_TOP 1
1694816948
#define PM_PARSE_PATTERN_MULTI 2
1694916949

16950+
typedef struct {
16951+
bool in_alternative_pattern;
16952+
bool capture_in_pattern;
16953+
} pm_pattern_capturing_t;
16954+
1695016955
static pm_node_t *
1695116956
parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth);
1695216957

@@ -16956,13 +16961,16 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
1695616961
* an error to the parser.
1695716962
*/
1695816963
static void
16959-
parse_pattern_capture(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_constant_id_t capture, const pm_location_t *location) {
16964+
parse_pattern_capture(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_constant_id_t capture, const pm_location_t *location, pm_pattern_capturing_t *capturing) {
1696016965
// Skip this capture if it starts with an underscore.
1696116966
if (*location->start == '_') return;
1696216967

1696316968
if (pm_constant_id_list_includes(captures, capture)) {
1696416969
pm_parser_err(parser, location->start, location->end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16970+
} else if (capturing->in_alternative_pattern && parser->version >= PM_OPTIONS_VERSION_CRUBY_3_5) {
16971+
pm_parser_err(parser, location->start, location->end, PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE);
1696516972
} else {
16973+
capturing->capture_in_pattern = true;
1696616974
pm_constant_id_list_append(captures, capture);
1696716975
}
1696816976
}
@@ -17091,7 +17099,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
1709117099
* Parse a rest pattern.
1709217100
*/
1709317101
static pm_splat_node_t *
17094-
parse_pattern_rest(pm_parser_t *parser, pm_constant_id_list_t *captures) {
17102+
parse_pattern_rest(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_pattern_capturing_t *capturing) {
1709517103
assert(parser->previous.type == PM_TOKEN_USTAR);
1709617104
pm_token_t operator = parser->previous;
1709717105
pm_node_t *name = NULL;
@@ -17108,7 +17116,7 @@ parse_pattern_rest(pm_parser_t *parser, pm_constant_id_list_t *captures) {
1710817116
pm_parser_local_add(parser, constant_id, identifier.start, identifier.end, 0);
1710917117
}
1711017118

17111-
parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
17119+
parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier), capturing);
1711217120
name = (pm_node_t *) pm_local_variable_target_node_create(
1711317121
parser,
1711417122
&PM_LOCATION_TOKEN_VALUE(&identifier),
@@ -17125,7 +17133,7 @@ parse_pattern_rest(pm_parser_t *parser, pm_constant_id_list_t *captures) {
1712517133
* Parse a keyword rest node.
1712617134
*/
1712717135
static pm_node_t *
17128-
parse_pattern_keyword_rest(pm_parser_t *parser, pm_constant_id_list_t *captures) {
17136+
parse_pattern_keyword_rest(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_pattern_capturing_t *capturing) {
1712917137
assert(parser->current.type == PM_TOKEN_USTAR_STAR);
1713017138
parser_lex(parser);
1713117139

@@ -17144,7 +17152,7 @@ parse_pattern_keyword_rest(pm_parser_t *parser, pm_constant_id_list_t *captures)
1714417152
pm_parser_local_add(parser, constant_id, parser->previous.start, parser->previous.end, 0);
1714517153
}
1714617154

17147-
parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous));
17155+
parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous), capturing);
1714817156
value = (pm_node_t *) pm_local_variable_target_node_create(
1714917157
parser,
1715017158
&PM_LOCATION_TOKEN_VALUE(&parser->previous),
@@ -17188,7 +17196,7 @@ pm_slice_is_valid_local(const pm_parser_t *parser, const uint8_t *start, const u
1718817196
* value. This will use an implicit local variable target.
1718917197
*/
1719017198
static pm_node_t *
17191-
parse_pattern_hash_implicit_value(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_symbol_node_t *key) {
17199+
parse_pattern_hash_implicit_value(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_symbol_node_t *key, pm_pattern_capturing_t *capturing) {
1719217200
const pm_location_t *value_loc = &((pm_symbol_node_t *) key)->value_loc;
1719317201

1719417202
pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, value_loc->start, value_loc->end);
@@ -17208,7 +17216,7 @@ parse_pattern_hash_implicit_value(pm_parser_t *parser, pm_constant_id_list_t *ca
1720817216
pm_parser_local_add(parser, constant_id, value_loc->start, value_loc->end, 0);
1720917217
}
1721017218

17211-
parse_pattern_capture(parser, captures, constant_id, value_loc);
17219+
parse_pattern_capture(parser, captures, constant_id, value_loc, capturing);
1721217220
pm_local_variable_target_node_t *target = pm_local_variable_target_node_create(
1721317221
parser,
1721417222
value_loc,
@@ -17234,7 +17242,7 @@ parse_pattern_hash_key(pm_parser_t *parser, pm_static_literals_t *keys, pm_node_
1723417242
* Parse a hash pattern.
1723517243
*/
1723617244
static pm_hash_pattern_node_t *
17237-
parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node_t *first_node, uint16_t depth) {
17245+
parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node_t *first_node, pm_pattern_capturing_t *capturing, uint16_t depth) {
1723817246
pm_node_list_t assocs = { 0 };
1723917247
pm_static_literals_t keys = { 0 };
1724017248
pm_node_t *rest = NULL;
@@ -17252,7 +17260,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
1725217260
if (match8(parser, PM_TOKEN_COMMA, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF)) {
1725317261
// Otherwise, we will create an implicit local variable
1725417262
// target for the value.
17255-
value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) first_node);
17263+
value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) first_node, capturing);
1725617264
} else {
1725717265
// Here we have a value for the first assoc in the list, so
1725817266
// we will parse it now.
@@ -17296,7 +17304,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
1729617304
}
1729717305

1729817306
if (match1(parser, PM_TOKEN_USTAR_STAR)) {
17299-
pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17307+
pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures, capturing);
1730017308

1730117309
if (rest == NULL) {
1730217310
rest = assoc;
@@ -17324,7 +17332,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
1732417332
pm_node_t *value = NULL;
1732517333

1732617334
if (match7(parser, PM_TOKEN_COMMA, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
17327-
value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) key);
17335+
value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) key, capturing);
1732817336
} else {
1732917337
value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
1733017338
}
@@ -17351,7 +17359,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
1735117359
* Parse a pattern expression primitive.
1735217360
*/
1735317361
static pm_node_t *
17354-
parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_diagnostic_id_t diag_id, uint16_t depth) {
17362+
parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_pattern_capturing_t *capturing, pm_diagnostic_id_t diag_id, uint16_t depth) {
1735517363
switch (parser->current.type) {
1735617364
case PM_TOKEN_IDENTIFIER:
1735717365
case PM_TOKEN_METHOD_NAME: {
@@ -17363,7 +17371,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
1736317371
pm_parser_local_add(parser, constant_id, parser->previous.start, parser->previous.end, 0);
1736417372
}
1736517373

17366-
parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous));
17374+
parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous), capturing);
1736717375
return (pm_node_t *) pm_local_variable_target_node_create(
1736817376
parser,
1736917377
&PM_LOCATION_TOKEN_VALUE(&parser->previous),
@@ -17447,7 +17455,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
1744717455
first_node = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->previous);
1744817456
break;
1744917457
case PM_TOKEN_USTAR_STAR:
17450-
first_node = parse_pattern_keyword_rest(parser, captures);
17458+
first_node = parse_pattern_keyword_rest(parser, captures, capturing);
1745117459
break;
1745217460
case PM_TOKEN_STRING_BEGIN:
1745317461
first_node = parse_expression(parser, PM_BINDING_POWER_MAX, false, true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
@@ -17461,7 +17469,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
1746117469
}
1746217470
}
1746317471

17464-
node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17472+
node = parse_pattern_hash(parser, captures, first_node, capturing, (uint16_t) (depth + 1));
1746517473

1746617474
accept1(parser, PM_TOKEN_NEWLINE);
1746717475
expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE);
@@ -17629,10 +17637,18 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
1762917637
static pm_node_t *
1763017638
parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node_t *first_node, pm_diagnostic_id_t diag_id, uint16_t depth) {
1763117639
pm_node_t *node = first_node;
17640+
pm_pattern_capturing_t capturing = { false, false };
1763217641

1763317642
while ((node == NULL) || accept1(parser, PM_TOKEN_PIPE)) {
1763417643
pm_token_t operator = parser->previous;
1763517644

17645+
if (node) {
17646+
if (capturing.capture_in_pattern) {
17647+
pm_parser_err(parser, operator.start, operator.end, PM_ERR_PATTERN_ALTERNATIVE_AFTER_CAPTURE);
17648+
}
17649+
capturing.in_alternative_pattern = true;
17650+
}
17651+
1763617652
switch (parser->current.type) {
1763717653
case PM_TOKEN_IDENTIFIER:
1763817654
case PM_TOKEN_BRACKET_LEFT_ARRAY:
@@ -17644,9 +17660,9 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p
1764417660
case PM_TOKEN_UDOT_DOT_DOT:
1764517661
case PM_CASE_PRIMITIVE: {
1764617662
if (node == NULL) {
17647-
node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17663+
node = parse_pattern_primitive(parser, captures, &capturing, diag_id, (uint16_t) (depth + 1));
1764817664
} else {
17649-
pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17665+
pm_node_t *right = parse_pattern_primitive(parser, captures, &capturing, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
1765017666
node = (pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &operator);
1765117667
}
1765217668

@@ -17698,7 +17714,7 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p
1769817714
pm_parser_local_add(parser, constant_id, parser->previous.start, parser->previous.end, 0);
1769917715
}
1770017716

17701-
parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous));
17717+
parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous), &capturing);
1770217718
pm_local_variable_target_node_t *target = pm_local_variable_target_node_create(
1770317719
parser,
1770417720
&PM_LOCATION_TOKEN_VALUE(&parser->previous),
@@ -17721,12 +17737,13 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
1772117737

1772217738
bool leading_rest = false;
1772317739
bool trailing_rest = false;
17740+
pm_pattern_capturing_t capturing = { false, false };
1772417741

1772517742
switch (parser->current.type) {
1772617743
case PM_TOKEN_LABEL: {
1772717744
parser_lex(parser);
1772817745
pm_node_t *key = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->previous);
17729-
node = (pm_node_t *) parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1));
17746+
node = (pm_node_t *) parse_pattern_hash(parser, captures, key, &capturing, (uint16_t) (depth + 1));
1773017747

1773117748
if (!(flags & PM_PARSE_PATTERN_TOP)) {
1773217749
pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
@@ -17735,8 +17752,8 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
1773517752
return node;
1773617753
}
1773717754
case PM_TOKEN_USTAR_STAR: {
17738-
node = parse_pattern_keyword_rest(parser, captures);
17739-
node = (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17755+
node = parse_pattern_keyword_rest(parser, captures, &capturing);
17756+
node = (pm_node_t *) parse_pattern_hash(parser, captures, node, &capturing, (uint16_t) (depth + 1));
1774017757

1774117758
if (!(flags & PM_PARSE_PATTERN_TOP)) {
1774217759
pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
@@ -17747,10 +17764,10 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
1774717764
case PM_TOKEN_STRING_BEGIN: {
1774817765
// We need special handling for string beginnings because they could
1774917766
// be dynamic symbols leading to hash patterns.
17750-
node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17767+
node = parse_pattern_primitive(parser, captures, &capturing, diag_id, (uint16_t) (depth + 1));
1775117768

1775217769
if (pm_symbol_node_label_p(node)) {
17753-
node = (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17770+
node = (pm_node_t *) parse_pattern_hash(parser, captures, node, &capturing, (uint16_t) (depth + 1));
1775417771

1775517772
if (!(flags & PM_PARSE_PATTERN_TOP)) {
1775617773
pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
@@ -17765,7 +17782,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
1776517782
case PM_TOKEN_USTAR: {
1776617783
if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
1776717784
parser_lex(parser);
17768-
node = (pm_node_t *) parse_pattern_rest(parser, captures);
17785+
node = (pm_node_t *) parse_pattern_rest(parser, captures, &capturing);
1776917786
leading_rest = true;
1777017787
break;
1777117788
}
@@ -17779,7 +17796,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
1777917796
// If we got a dynamic label symbol, then we need to treat it like the
1778017797
// beginning of a hash pattern.
1778117798
if (pm_symbol_node_label_p(node)) {
17782-
return (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17799+
return (pm_node_t *) parse_pattern_hash(parser, captures, node, &capturing, (uint16_t) (depth + 1));
1778317800
}
1778417801

1778517802
if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
@@ -17800,7 +17817,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
1780017817
}
1780117818

1780217819
if (accept1(parser, PM_TOKEN_USTAR)) {
17803-
node = (pm_node_t *) parse_pattern_rest(parser, captures);
17820+
node = (pm_node_t *) parse_pattern_rest(parser, captures, &capturing);
1780417821

1780517822
// If we have already parsed a splat pattern, then this is an
1780617823
// error. We will continue to parse the rest of the patterns,

templates/src/diagnostic.c.erb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,8 +299,10 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
299299
[PM_ERR_PARAMETER_UNEXPECTED_FWD] = { "unexpected `...` in parameters", PM_ERROR_LEVEL_SYNTAX },
300300
[PM_ERR_PARAMETER_WILD_LOOSE_COMMA] = { "unexpected `,` in parameters", PM_ERROR_LEVEL_SYNTAX },
301301
[PM_ERR_PARAMETER_UNEXPECTED_NO_KW] = { "unexpected **nil; no keywords marker disallowed after keywords", PM_ERROR_LEVEL_SYNTAX },
302+
[PM_ERR_PATTERN_ALTERNATIVE_AFTER_CAPTURE] = { "alternative pattern after variable capture", PM_ERROR_LEVEL_SYNTAX },
302303
[PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS] = { "unexpected multiple '*' rest patterns in an array pattern", PM_ERROR_LEVEL_SYNTAX },
303304
[PM_ERR_PATTERN_CAPTURE_DUPLICATE] = { "duplicated variable name", PM_ERROR_LEVEL_SYNTAX },
305+
[PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE] = { "variable capture in alternative pattern", PM_ERROR_LEVEL_SYNTAX },
304306
[PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET] = { "expected a pattern expression after the `[` operator", PM_ERROR_LEVEL_SYNTAX },
305307
[PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA] = { "expected a pattern expression after `,`", PM_ERROR_LEVEL_SYNTAX },
306308
[PM_ERR_PATTERN_EXPRESSION_AFTER_HROCKET] = { "expected a pattern expression after `=>`", PM_ERROR_LEVEL_SYNTAX },

test/prism/result/source_location_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def test_AliasMethodNode
1313
end
1414

1515
def test_AlternationPatternNode
16-
assert_location(AlternationPatternNode, "foo => bar | baz", 7...16, &:pattern)
16+
assert_location(AlternationPatternNode, "foo => 0 | 1", 7...12, &:pattern)
1717
end
1818

1919
def test_AndNode

0 commit comments

Comments
 (0)