@@ -1054,6 +1054,13 @@ pm_parser_constant_id_token(pm_parser_t *parser, const pm_token_t *token) {
10541054 return pm_parser_constant_id_raw(parser, token->start, token->end);
10551055}
10561056
1057+ /**
1058+ * This macro allows you to define a case statement for all of the nodes that
1059+ * may result in a void value.
1060+ */
1061+ #define PM_CASE_VOID_VALUE PM_RETURN_NODE: case PM_BREAK_NODE: case PM_NEXT_NODE: \
1062+ case PM_REDO_NODE: case PM_RETRY_NODE: case PM_MATCH_REQUIRED_NODE
1063+
10571064/**
10581065 * Check whether or not the given node is value expression.
10591066 * If the node is value node, it returns NULL.
@@ -1065,12 +1072,7 @@ pm_check_value_expression(pm_parser_t *parser, pm_node_t *node) {
10651072
10661073 while (node != NULL) {
10671074 switch (PM_NODE_TYPE(node)) {
1068- case PM_RETURN_NODE:
1069- case PM_BREAK_NODE:
1070- case PM_NEXT_NODE:
1071- case PM_REDO_NODE:
1072- case PM_RETRY_NODE:
1073- case PM_MATCH_REQUIRED_NODE:
1075+ case PM_CASE_VOID_VALUE:
10741076 return void_node != NULL ? void_node : node;
10751077 case PM_MATCH_PREDICATE_NODE:
10761078 return NULL;
@@ -1090,25 +1092,36 @@ pm_check_value_expression(pm_parser_t *parser, pm_node_t *node) {
10901092
10911093 node = UP(cast->ensure_clause);
10921094 } else if (cast->rescue_clause != NULL) {
1093- if (cast->statements == NULL) return NULL;
1095+ // https://bugs.ruby-lang.org/issues/21669
1096+ if (cast->else_clause == NULL || parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1097+ if (cast->statements == NULL) return NULL;
10941098
1095- pm_node_t *vn = pm_check_value_expression(parser, UP(cast->statements));
1096- if (vn == NULL) return NULL;
1097- if (void_node == NULL) void_node = vn;
1099+ pm_node_t *vn = pm_check_value_expression(parser, UP(cast->statements));
1100+ if (vn == NULL) return NULL;
1101+ if (void_node == NULL) void_node = vn;
1102+ }
10981103
10991104 for (pm_rescue_node_t *rescue_clause = cast->rescue_clause; rescue_clause != NULL; rescue_clause = rescue_clause->subsequent) {
11001105 pm_node_t *vn = pm_check_value_expression(parser, UP(rescue_clause->statements));
1106+
11011107 if (vn == NULL) {
1108+ // https://bugs.ruby-lang.org/issues/21669
1109+ if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1110+ return NULL;
1111+ }
11021112 void_node = NULL;
11031113 break;
11041114 }
1105- if (void_node == NULL) {
1106- void_node = vn;
1107- }
11081115 }
11091116
11101117 if (cast->else_clause != NULL) {
11111118 node = UP(cast->else_clause);
1119+
1120+ // https://bugs.ruby-lang.org/issues/21669
1121+ if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1122+ pm_node_t *vn = pm_check_value_expression(parser, node);
1123+ if (vn != NULL) return vn;
1124+ }
11121125 } else {
11131126 return void_node;
11141127 }
@@ -1118,6 +1131,50 @@ pm_check_value_expression(pm_parser_t *parser, pm_node_t *node) {
11181131
11191132 break;
11201133 }
1134+ case PM_CASE_NODE: {
1135+ // https://bugs.ruby-lang.org/issues/21669
1136+ if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1137+ return NULL;
1138+ }
1139+
1140+ pm_case_node_t *cast = (pm_case_node_t *) node;
1141+ if (cast->else_clause == NULL) return NULL;
1142+
1143+ pm_node_t *condition;
1144+ PM_NODE_LIST_FOREACH(&cast->conditions, index, condition) {
1145+ assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
1146+
1147+ pm_when_node_t *cast = (pm_when_node_t *) condition;
1148+ pm_node_t *vn = pm_check_value_expression(parser, UP(cast->statements));
1149+ if (vn == NULL) return NULL;
1150+ if (void_node == NULL) void_node = vn;
1151+ }
1152+
1153+ node = UP(cast->else_clause);
1154+ break;
1155+ }
1156+ case PM_CASE_MATCH_NODE: {
1157+ // https://bugs.ruby-lang.org/issues/21669
1158+ if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1159+ return NULL;
1160+ }
1161+
1162+ pm_case_match_node_t *cast = (pm_case_match_node_t *) node;
1163+ if (cast->else_clause == NULL) return NULL;
1164+
1165+ pm_node_t *condition;
1166+ PM_NODE_LIST_FOREACH(&cast->conditions, index, condition) {
1167+ assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
1168+
1169+ pm_in_node_t *cast = (pm_in_node_t *) condition;
1170+ pm_node_t *vn = pm_check_value_expression(parser, UP(cast->statements));
1171+ if (vn == NULL) return NULL;
1172+ if (void_node == NULL) void_node = vn;
1173+ }
1174+
1175+ node = UP(cast->else_clause);
1176+ break;
1177+ }
11211178 case PM_ENSURE_NODE: {
11221179 pm_ensure_node_t *cast = (pm_ensure_node_t *) node;
11231180 node = UP(cast->statements);
@@ -1130,6 +1187,22 @@ pm_check_value_expression(pm_parser_t *parser, pm_node_t *node) {
11301187 }
11311188 case PM_STATEMENTS_NODE: {
11321189 pm_statements_node_t *cast = (pm_statements_node_t *) node;
1190+
1191+ // https://bugs.ruby-lang.org/issues/21669
1192+ if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1193+ pm_node_t *body_part;
1194+ PM_NODE_LIST_FOREACH(&cast->body, index, body_part) {
1195+ switch (PM_NODE_TYPE(body_part)) {
1196+ case PM_CASE_VOID_VALUE:
1197+ if (void_node == NULL) {
1198+ void_node = body_part;
1199+ }
1200+ return void_node;
1201+ default: break;
1202+ }
1203+ }
1204+ }
1205+
11331206 node = cast->body.nodes[cast->body.size - 1];
11341207 break;
11351208 }
0 commit comments