summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTSUYUSATO Kitsune <make.just.on@gmail.com>2023-11-13 16:03:03 +0900
committergit <svn-admin@ruby-lang.org>2023-11-14 14:34:47 +0000
commit52a0f1d14b76e4b095fc61323f669b1a1d6be960 (patch)
treefefce3cb7317be125c8123ef1af39734f1d5826b
parent26d11383e548dccd7493079daeb9626c059aa87f (diff)
[ruby/prism] Add "Unexpected void value expression" error
https://github.com/ruby/prism/commit/88b7b8e1fc
-rw-r--r--prism/diagnostic.c1
-rw-r--r--prism/diagnostic.h1
-rw-r--r--prism/prism.c96
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:
*