diff options
| author | TSUYUSATO Kitsune <make.just.on@gmail.com> | 2023-11-13 16:03:03 +0900 |
|---|---|---|
| committer | git <svn-admin@ruby-lang.org> | 2023-11-14 14:34:47 +0000 |
| commit | 52a0f1d14b76e4b095fc61323f669b1a1d6be960 (patch) | |
| tree | fefce3cb7317be125c8123ef1af39734f1d5826b | |
| parent | 26d11383e548dccd7493079daeb9626c059aa87f (diff) | |
[ruby/prism] Add "Unexpected void value expression" error
https://github.com/ruby/prism/commit/88b7b8e1fc
| -rw-r--r-- | prism/diagnostic.c | 1 | ||||
| -rw-r--r-- | prism/diagnostic.h | 1 | ||||
| -rw-r--r-- | prism/prism.c | 96 |
3 files changed, 98 insertions, 0 deletions
diff --git a/prism/diagnostic.c b/prism/diagnostic.c index fdeb9cab12..2c59e4effc 100644 --- a/prism/diagnostic.c +++ b/prism/diagnostic.c @@ -244,6 +244,7 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = { [PM_ERR_UNARY_RECEIVER_PLUS] = "Expected a receiver for unary `+`", [PM_ERR_UNARY_RECEIVER_TILDE] = "Expected a receiver for unary `~`", [PM_ERR_UNTIL_TERM] = "Expected an `end` to close the `until` statement", + [PM_ERR_VOID_EXPRESSION] = "Unexpected void value expression", [PM_ERR_WHILE_TERM] = "Expected an `end` to close the `while` statement", [PM_ERR_WRITE_TARGET_READONLY] = "Immutable variable as a write target", [PM_ERR_WRITE_TARGET_UNEXPECTED] = "Unexpected write target", diff --git a/prism/diagnostic.h b/prism/diagnostic.h index 97bd83fdf7..10b547ae20 100644 --- a/prism/diagnostic.h +++ b/prism/diagnostic.h @@ -231,6 +231,7 @@ typedef enum { PM_ERR_UNARY_RECEIVER_TILDE, PM_ERR_UNDEF_ARGUMENT, PM_ERR_UNTIL_TERM, + PM_ERR_VOID_EXPRESSION, PM_ERR_WHILE_TERM, PM_ERR_WRITE_TARGET_READONLY, PM_ERR_WRITE_TARGET_UNEXPECTED, diff --git a/prism/prism.c b/prism/prism.c index 15e550d245..b42c02be18 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -568,6 +568,102 @@ pm_parser_optional_constant_id_token(pm_parser_t *parser, const pm_token_t *toke } /** + * Check whether or not the given node is value expression. + * If the node is value node, it returns NULL. + * If not, it returns the pointer to the node to be inspected as "void expression". + */ +static pm_node_t* +pm_check_value_expression(pm_node_t *node) { + pm_node_t* void_node = NULL; + + while (node != NULL) { + switch (PM_NODE_TYPE(node)) { + case PM_RETURN_NODE: + case PM_BREAK_NODE: + case PM_NEXT_NODE: + case PM_REDO_NODE: + case PM_RETRY_NODE: + case PM_MATCH_REQUIRED_NODE: + return void_node != NULL ? void_node : node; + case PM_MATCH_PREDICATE_NODE: + return NULL; + case PM_BEGIN_NODE: { + pm_begin_node_t *cast = (pm_begin_node_t *) node; + node = (pm_node_t *) cast->statements; + break; + } + case PM_PARENTHESES_NODE: { + pm_parentheses_node_t *cast = (pm_parentheses_node_t *) node; + node = (pm_node_t *) cast->body; + break; + } + case PM_STATEMENTS_NODE: { + pm_statements_node_t *cast = (pm_statements_node_t *) node; + node = cast->body.nodes[cast->body.size - 1]; + break; + } + case PM_IF_NODE: { + pm_if_node_t *cast = (pm_if_node_t *) node; + if (cast->statements == NULL || cast->consequent == NULL) { + return NULL; + } + pm_node_t *vn = pm_check_value_expression((pm_node_t *) cast->statements); + if (vn == NULL) { + return NULL; + } + if (void_node == NULL) { + void_node = vn; + } + node = cast->consequent; + break; + } + case PM_UNLESS_NODE: { + pm_unless_node_t *cast = (pm_unless_node_t *) node; + if (cast->statements == NULL || cast->consequent == NULL) { + return NULL; + } + pm_node_t *vn = pm_check_value_expression((pm_node_t *) cast->statements); + if (vn == NULL) { + return NULL; + } + if (void_node == NULL) { + void_node = vn; + } + node = (pm_node_t *) cast->consequent; + break; + } + case PM_ELSE_NODE: { + pm_else_node_t *cast = (pm_else_node_t *) node; + node = (pm_node_t *) cast->statements; + break; + } + case PM_AND_NODE: { + pm_and_node_t *cast = (pm_and_node_t *) node; + node = cast->left; + break; + } + case PM_OR_NODE: { + pm_or_node_t *cast = (pm_or_node_t *) node; + node = cast->left; + break; + } + default: + return NULL; + } + } + + return NULL; +} + +static inline void +pm_assert_value_expression(pm_parser_t *parser, pm_node_t *node) { + pm_node_t *void_node = pm_check_value_expression(node); + if (void_node != NULL) { + pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION); + } +} + +/** * The predicate of conditional nodes can change what would otherwise be regular * nodes into specialized nodes. For example: * |
