summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2024-10-07 13:47:04 -0400
committergit <svn-admin@ruby-lang.org>2024-10-07 17:57:36 +0000
commit4cbd2ab9d462784ee44108e396177807e869ad23 (patch)
tree06c776233aa4ba8d6c4c4eced4191e26aedb3c68
parent35711903f239e462da682929982f434ee45c2199 (diff)
[ruby/prism] Properly handle non-assoc operators
https://github.com/ruby/prism/commit/dbd5c929d6
-rw-r--r--prism/prism.c14
-rw-r--r--test/prism/errors/binary_range_with_left_unary_range.txt1
-rw-r--r--test/prism/errors/non_assoc_equality.txt6
-rw-r--r--test/prism/errors/range_and_bin_op.txt1
-rw-r--r--test/prism/errors/range_and_bin_op_2.txt1
5 files changed, 21 insertions, 2 deletions
diff --git a/prism/prism.c b/prism/prism.c
index b88c99c659..7ef92ef5a5 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -21764,8 +21764,11 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
// Otherwise we'll look and see if the next token can be parsed as an infix
// operator. If it can, then we'll parse it using parse_expression_infix.
pm_binding_powers_t current_binding_powers;
+ pm_token_type_t current_token_type;
+
while (
- current_binding_powers = pm_binding_powers[parser->current.type],
+ current_token_type = parser->current.type,
+ current_binding_powers = pm_binding_powers[current_token_type],
binding_power <= current_binding_powers.left &&
current_binding_powers.binary
) {
@@ -21806,6 +21809,13 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
// If the operator is nonassoc and we should not be able to parse the
// upcoming infix operator, break.
if (current_binding_powers.nonassoc) {
+ // If this is a non-assoc operator and we are about to parse the
+ // exact same operator, then we need to add an error.
+ if (match1(parser, current_token_type)) {
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_type_human(parser->current.type), pm_token_type_human(current_token_type));
+ break;
+ }
+
// If this is an endless range, then we need to reject a couple of
// additional operators because it violates the normal operator
// precedence rules. Those patterns are:
@@ -21815,7 +21825,7 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
//
if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((pm_range_node_t *) node)->right == NULL) {
if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_type_human(parser->current.type), pm_token_type_human(parser->previous.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_type_human(parser->current.type), pm_token_type_human(current_token_type));
break;
}
diff --git a/test/prism/errors/binary_range_with_left_unary_range.txt b/test/prism/errors/binary_range_with_left_unary_range.txt
index 37e41f3971..85cf55fb80 100644
--- a/test/prism/errors/binary_range_with_left_unary_range.txt
+++ b/test/prism/errors/binary_range_with_left_unary_range.txt
@@ -2,6 +2,7 @@
^~ unexpected range operator; .. and ... are non-associative and cannot be chained
...1..
^~ unexpected range operator; .. and ... are non-associative and cannot be chained
+ ^~ unexpected ..; .. is a non-associative operator
^~ unexpected .., expecting end-of-input
^~ unexpected .., ignoring it
diff --git a/test/prism/errors/non_assoc_equality.txt b/test/prism/errors/non_assoc_equality.txt
index 6ce8da88d6..9b3f137549 100644
--- a/test/prism/errors/non_assoc_equality.txt
+++ b/test/prism/errors/non_assoc_equality.txt
@@ -1,19 +1,25 @@
1 == 2 == 3
+ ^~ unexpected '=='; '==' is a non-associative operator
^~ unexpected '==', expecting end-of-input
^~ unexpected '==', ignoring it
1 != 2 != 3
+ ^~ unexpected '!='; '!=' is a non-associative operator
^~ unexpected '!=', expecting end-of-input
^~ unexpected '!=', ignoring it
1 === 2 === 3
+ ^~~ unexpected '==='; '===' is a non-associative operator
^~~ unexpected '===', expecting end-of-input
^~~ unexpected '===', ignoring it
1 =~ 2 =~ 3
+ ^~ unexpected '=~'; '=~' is a non-associative operator
^~ unexpected '=~', expecting end-of-input
^~ unexpected '=~', ignoring it
1 !~ 2 !~ 3
+ ^~ unexpected '!~'; '!~' is a non-associative operator
^~ unexpected '!~', expecting end-of-input
^~ unexpected '!~', ignoring it
1 <=> 2 <=> 3
+ ^~~ unexpected '<=>'; '<=>' is a non-associative operator
^~~ unexpected '<=>', expecting end-of-input
^~~ unexpected '<=>', ignoring it
diff --git a/test/prism/errors/range_and_bin_op.txt b/test/prism/errors/range_and_bin_op.txt
index 4a7a396d0d..55928c409b 100644
--- a/test/prism/errors/range_and_bin_op.txt
+++ b/test/prism/errors/range_and_bin_op.txt
@@ -1,4 +1,5 @@
1..2..3
+ ^~ unexpected ..; .. is a non-associative operator
^~ unexpected .., expecting end-of-input
^~ unexpected .., ignoring it
diff --git a/test/prism/errors/range_and_bin_op_2.txt b/test/prism/errors/range_and_bin_op_2.txt
index f2a31dcf82..6ca91a26eb 100644
--- a/test/prism/errors/range_and_bin_op_2.txt
+++ b/test/prism/errors/range_and_bin_op_2.txt
@@ -1,4 +1,5 @@
1..2..
+ ^~ unexpected ..; .. is a non-associative operator
^~ unexpected .., expecting end-of-input
^~ unexpected .., ignoring it