Skip to content

Commit

Permalink
Merge pull request #3167 from ruby/properly-handle-nonassoc
Browse files Browse the repository at this point in the history
Properly handle non-assoc operators
  • Loading branch information
kddnewton authored Oct 7, 2024
2 parents a97f341 + dbd5c92 commit c1a27a5
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 2 deletions.
14 changes: 12 additions & 2 deletions src/prism.c
Original file line number Diff line number Diff line change
Expand Up @@ -21765,8 +21765,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
) {
Expand Down Expand Up @@ -21807,6 +21810,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:
Expand All @@ -21816,7 +21826,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;
}

Expand Down
1 change: 1 addition & 0 deletions test/prism/errors/binary_range_with_left_unary_range.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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

6 changes: 6 additions & 0 deletions test/prism/errors/non_assoc_equality.txt
Original file line number Diff line number Diff line change
@@ -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

1 change: 1 addition & 0 deletions test/prism/errors/range_and_bin_op.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
1..2..3
^~ unexpected ..; .. is a non-associative operator
^~ unexpected .., expecting end-of-input
^~ unexpected .., ignoring it

1 change: 1 addition & 0 deletions test/prism/errors/range_and_bin_op_2.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
1..2..
^~ unexpected ..; .. is a non-associative operator
^~ unexpected .., expecting end-of-input
^~ unexpected .., ignoring it

0 comments on commit c1a27a5

Please sign in to comment.