aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2024-06-14 15:09:25 -0400
committergit <svn-admin@ruby-lang.org>2024-06-14 19:22:54 +0000
commit7529591df11563fa29e19716322ca03b0c6d3e3e (patch)
tree3f07b5f16a07af8ae8726b12f7a404a96c461990
parent4d73f3f9ebefa347acc1ec8031ac4025f5f71ba8 (diff)
downloadruby-7529591df11563fa29e19716322ca03b0c6d3e3e.tar.gz
[ruby/prism] Ensure ranges are non-associative
https://github.com/ruby/prism/commit/f59295938b
-rw-r--r--prism/config.yml1
-rw-r--r--prism/prism.c18
-rw-r--r--prism/templates/src/diagnostic.c.erb1
-rw-r--r--test/prism/errors_test.rb4
4 files changed, 13 insertions, 11 deletions
diff --git a/prism/config.yml b/prism/config.yml
index 9b54982106..98443af774 100644
--- a/prism/config.yml
+++ b/prism/config.yml
@@ -267,6 +267,7 @@ errors:
- UNEXPECTED_INDEX_BLOCK
- UNEXPECTED_INDEX_KEYWORDS
- UNEXPECTED_MULTI_WRITE
+ - UNEXPECTED_RANGE_OPERATOR
- UNEXPECTED_SAFE_NAVIGATION
- UNEXPECTED_TOKEN_CLOSE_CONTEXT
- UNEXPECTED_TOKEN_IGNORE
diff --git a/prism/prism.c b/prism/prism.c
index 6b094715e6..2c9d3d9c56 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -17737,6 +17737,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
parser_lex(parser);
pm_node_t *right = parse_expression(parser, pm_binding_powers[operator.type].left, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+
+ // Unary .. and ... are special because these are non-associative
+ // operators that can also be unary operators. In this case we need
+ // to explicitly reject code that has a .. or ... that follows this
+ // expression.
+ if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
+ pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
+ }
+
return (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right);
}
case PM_TOKEN_FLOAT:
@@ -20987,15 +20996,6 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
return node;
}
break;
- case PM_RANGE_NODE:
- // Range operators are non-associative, so that it does not
- // associate with other range operators (i.e. `..1..` should be
- // rejected). For this reason, we check such a case for unary ranges
- // here, and if so, it returns the node immediately.
- if ((((pm_range_node_t *) node)->left == NULL) && pm_binding_powers[parser->current.type].left >= PM_BINDING_POWER_RANGE) {
- return node;
- }
- break;
default:
break;
}
diff --git a/prism/templates/src/diagnostic.c.erb b/prism/templates/src/diagnostic.c.erb
index 1fc3e6047e..f94f83a7a1 100644
--- a/prism/templates/src/diagnostic.c.erb
+++ b/prism/templates/src/diagnostic.c.erb
@@ -348,6 +348,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_UNEXPECTED_INDEX_BLOCK] = { "unexpected block arg given in index assignment; blocks are not allowed in index assignment expressions", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_INDEX_KEYWORDS] = { "unexpected keyword arg given in index assignment; keywords are not allowed in index assignment expressions", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_MULTI_WRITE] = { "unexpected multiple assignment; multiple assignment is not allowed in this context", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_UNEXPECTED_RANGE_OPERATOR] = { "unexpected range operator; .. and ... are non-associative and cannot be chained", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_SAFE_NAVIGATION] = { "&. inside multiple assignment destination", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT] = { "unexpected %s, assuming it is closing the parent %s", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_TOKEN_IGNORE] = { "unexpected %s, ignoring it", PM_ERROR_LEVEL_SYNTAX },
diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb
index 91ba6ea373..2d8ddd7a11 100644
--- a/test/prism/errors_test.rb
+++ b/test/prism/errors_test.rb
@@ -1975,8 +1975,8 @@ module Prism
RUBY
assert_errors expression(source), source, [
- ["unexpected .., expecting end-of-input", 3..5],
- ["unexpected .., ignoring it", 3..5],
+ ["unexpected range operator; .. and ... are non-associative and cannot be chained", 3..5],
+ ["unexpected range operator; .. and ... are non-associative and cannot be chained", 10..12],
["unexpected .., expecting end-of-input", 10..12],
["unexpected .., ignoring it", 10..12]
]