@@ -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+
1695016955static pm_node_t *
1695116956parse_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 */
1695816963static 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 */
1709317101static 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 */
1712717135static 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 */
1719017198static 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 */
1723617244static 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 */
1735317361static 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
1762917637static pm_node_t *
1763017638parse_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,
0 commit comments