diff options
author | Kevin Newton <kddnewton@gmail.com> | 2023-11-20 21:38:03 -0500 |
---|---|---|
committer | git <svn-admin@ruby-lang.org> | 2023-11-21 02:38:07 +0000 |
commit | 9fa524dd41be60654e8515f9e406f6f47f0ac7fa (patch) | |
tree | 5cf2d3b62ba1f0ad68f98d85e3d76077164a6fb3 /prism | |
parent | 73d519ec461bee7c06e37abcb808443a05ec5a21 (diff) | |
download | ruby-9fa524dd41be60654e8515f9e406f6f47f0ac7fa.tar.gz |
[ruby/prism] Split up CaseNode and CaseMatchNode
(https://github.com/ruby/prism/pull/1801)
https://github.com/ruby/prism/commit/4c1391ea56
Diffstat (limited to 'prism')
-rw-r--r-- | prism/config.yml | 20 | ||||
-rw-r--r-- | prism/diagnostic.c | 1 | ||||
-rw-r--r-- | prism/diagnostic.h | 1 | ||||
-rw-r--r-- | prism/prism.c | 111 |
4 files changed, 119 insertions, 14 deletions
diff --git a/prism/config.yml b/prism/config.yml index 052901734a..ef12f7a730 100644 --- a/prism/config.yml +++ b/prism/config.yml @@ -768,6 +768,26 @@ nodes: foo => [bar => baz] ^^^^^^^^^^^^ + - name: CaseMatchNode + fields: + - name: predicate + type: node? + - name: conditions + type: node[] + - name: consequent + type: node? + kind: ElseNode + - name: case_keyword_loc + type: location + - name: end_keyword_loc + type: location + comment: | + Represents the use of a case statement for pattern matching. + + case true + in false + end + ^^^^^^^^^ - name: CaseNode fields: - name: predicate diff --git a/prism/diagnostic.c b/prism/diagnostic.c index c1d930a430..b6a4e291a7 100644 --- a/prism/diagnostic.c +++ b/prism/diagnostic.c @@ -87,6 +87,7 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = { [PM_ERR_CANNOT_PARSE_STRING_PART] = "Cannot parse the string part", [PM_ERR_CASE_EXPRESSION_AFTER_CASE] = "Expected an expression after `case`", [PM_ERR_CASE_EXPRESSION_AFTER_WHEN] = "Expected an expression after `when`", + [PM_ERR_CASE_MATCH_MISSING_PREDICATE] = "Expected a predicate for a case matching statement", [PM_ERR_CASE_MISSING_CONDITIONS] = "Expected a `when` or `in` clause after `case`", [PM_ERR_CASE_TERM] = "Expected an `end` to close the `case` statement", [PM_ERR_CLASS_IN_METHOD] = "Unexpected class definition in a method body", diff --git a/prism/diagnostic.h b/prism/diagnostic.h index c963289cbf..92bc88953e 100644 --- a/prism/diagnostic.h +++ b/prism/diagnostic.h @@ -73,6 +73,7 @@ typedef enum { PM_ERR_CANNOT_PARSE_STRING_PART, PM_ERR_CASE_EXPRESSION_AFTER_CASE, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, + PM_ERR_CASE_MATCH_MISSING_PREDICATE, PM_ERR_CASE_MISSING_CONDITIONS, PM_ERR_CASE_TERM, PM_ERR_CLASS_IN_METHOD, diff --git a/prism/prism.c b/prism/prism.c index 7330063bd8..48b6311d2f 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -2113,7 +2113,7 @@ pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t * Allocate and initialize a new CaseNode node. */ static pm_case_node_t * -pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, pm_else_node_t *consequent, const pm_token_t *end_keyword) { +pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) { pm_case_node_t *node = PM_ALLOC_NODE(parser, pm_case_node_t); *node = (pm_case_node_t) { @@ -2125,7 +2125,7 @@ pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node }, }, .predicate = predicate, - .consequent = consequent, + .consequent = NULL, .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword), .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword), .conditions = { 0 } @@ -2139,7 +2139,7 @@ pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node */ static void pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) { - assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE) || PM_NODE_TYPE_P(condition, PM_IN_NODE)); + assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE)); pm_node_list_append(&node->conditions, condition); node->base.location.end = condition->location.end; @@ -2164,6 +2164,60 @@ pm_case_node_end_keyword_loc_set(pm_case_node_t *node, const pm_token_t *end_key } /** + * Allocate and initialize a new CaseMatchNode node. + */ +static pm_case_match_node_t * +pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) { + pm_case_match_node_t *node = PM_ALLOC_NODE(parser, pm_case_match_node_t); + + *node = (pm_case_match_node_t) { + { + .type = PM_CASE_MATCH_NODE, + .location = { + .start = case_keyword->start, + .end = end_keyword->end + }, + }, + .predicate = predicate, + .consequent = NULL, + .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword), + .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword), + .conditions = { 0 } + }; + + return node; +} + +/** + * Append a new condition to a CaseMatchNode node. + */ +static void +pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) { + assert(PM_NODE_TYPE_P(condition, PM_IN_NODE)); + + pm_node_list_append(&node->conditions, condition); + node->base.location.end = condition->location.end; +} + +/** + * Set the consequent of a CaseMatchNode node. + */ +static void +pm_case_match_node_consequent_set(pm_case_match_node_t *node, pm_else_node_t *consequent) { + node->consequent = consequent; + node->base.location.end = consequent->base.location.end; +} + +/** + * Set the end location for a CaseMatchNode node. + */ +static void +pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_token_t *end_keyword) { + node->base.location.end = end_keyword->end; + node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword); +} + +/** * Allocate a new ClassNode node. */ static pm_class_node_t * @@ -14190,15 +14244,17 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { if (accept1(parser, PM_TOKEN_KEYWORD_END)) { pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS); - return (pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, NULL, &parser->previous); + return (pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, &parser->previous); } // At this point we can create a case node, though we don't yet know if it // is a case-in or case-when node. pm_token_t end_keyword = not_provided(parser); - pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, NULL, &end_keyword); + pm_node_t *node; if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) { + pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword); + // At this point we've seen a when keyword, so we know this is a // case-when node. We will continue to parse the when nodes until we hit // the end of the list. @@ -14238,7 +14294,23 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { pm_case_node_condition_append(case_node, (pm_node_t *) when_node); } + + // If we didn't parse any conditions (in or when) then we need + // to indicate that we have an error. + if (case_node->conditions.size == 0) { + pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS); + } + + node = (pm_node_t *) case_node; } else { + pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword); + + // If this is a case-match node (i.e., it is a pattern matching + // case statement) then we must have a predicate. + if (predicate == NULL) { + pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE); + } + // At this point we expect that we're parsing a case-in node. We will // continue to parse the in nodes until we hit the end of the list. while (match1(parser, PM_TOKEN_KEYWORD_IN)) { @@ -14292,14 +14364,16 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { // Now that we have the full pattern and statements, we can create the // node and attach it to the case node. pm_node_t *condition = (pm_node_t *) pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword); - pm_case_node_condition_append(case_node, condition); + pm_case_match_node_condition_append(case_node, condition); } - } - // If we didn't parse any conditions (in or when) then we need to - // indicate that we have an error. - if (case_node->conditions.size == 0) { - pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS); + // If we didn't parse any conditions (in or when) then we need + // to indicate that we have an error. + if (case_node->conditions.size == 0) { + pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS); + } + + node = (pm_node_t *) case_node; } accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); @@ -14313,12 +14387,21 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->current); } - pm_case_node_consequent_set(case_node, else_node); + if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) { + pm_case_node_consequent_set((pm_case_node_t *) node, else_node); + } else { + pm_case_match_node_consequent_set((pm_case_match_node_t *) node, else_node); + } } expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM); - pm_case_node_end_keyword_loc_set(case_node, &parser->previous); - return (pm_node_t *) case_node; + if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) { + pm_case_node_end_keyword_loc_set((pm_case_node_t *) node, &parser->previous); + } else { + pm_case_match_node_end_keyword_loc_set((pm_case_match_node_t *) node, &parser->previous); + } + + return node; } case PM_TOKEN_KEYWORD_BEGIN: { parser_lex(parser); |