Skip to content

Commit

Permalink
[ruby/prism] Fix multi write with modifier rescue
Browse files Browse the repository at this point in the history
  • Loading branch information
kddnewton authored and matzbot committed Feb 26, 2024
1 parent 815db5c commit 1a57fee
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 6 deletions.
14 changes: 8 additions & 6 deletions prism/prism.c
Original file line number Diff line number Diff line change
Expand Up @@ -17051,10 +17051,10 @@ parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_
static inline pm_node_t *
parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) {
pm_node_t *value = parse_starred_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH, diag_id);
bool single_value = true;

bool is_single_value = true;
if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
is_single_value = false;
single_value = false;
pm_token_t opening = not_provided(parser);
pm_array_node_t *array = pm_array_node_create(parser, &opening);

Expand All @@ -17068,16 +17068,18 @@ parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding
}
}

// Contradicting binding powers, the right-hand-side value of the assignment allows the `rescue` modifier.
if (is_single_value && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
// Contradicting binding powers, the right-hand-side value of the assignment
// allows the `rescue` modifier.
if ((single_value || (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1))) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
pm_token_t rescue = parser->current;
parser_lex(parser);

bool accepts_command_call_inner = false;

// RHS can accept command call iff the value is a call with arguments but without paranthesis.
// RHS can accept command call iff the value is a call with arguments
// but without paranthesis.
if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
pm_call_node_t *call_node = (pm_call_node_t *)value;
pm_call_node_t *call_node = (pm_call_node_t *) value;
if ((call_node->arguments != NULL) && (call_node->opening_loc.start == NULL)) {
accepts_command_call_inner = true;
}
Expand Down
4 changes: 4 additions & 0 deletions test/prism/fixtures/multi_write.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
foo = 1 rescue nil
foo, bar = 1 rescue nil
foo = 1, 2 rescue nil
foo, bar = 1, 2 rescue nil
1 change: 1 addition & 0 deletions test/prism/ruby_parser_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class RubyParserTest < TestCase
alias.txt
method_calls.txt
methods.txt
multi_write.txt
not.txt
patterns.txt
regex.txt
Expand Down
93 changes: 93 additions & 0 deletions test/prism/snapshots/multi_write.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
@ ProgramNode (location: (1,0)-(4,26))
├── locals: [:foo, :bar]
└── statements:
@ StatementsNode (location: (1,0)-(4,26))
└── body: (length: 4)
├── @ LocalVariableWriteNode (location: (1,0)-(1,18))
│ ├── name: :foo
│ ├── depth: 0
│ ├── name_loc: (1,0)-(1,3) = "foo"
│ ├── value:
│ │ @ RescueModifierNode (location: (1,6)-(1,18))
│ │ ├── expression:
│ │ │ @ IntegerNode (location: (1,6)-(1,7))
│ │ │ ├── flags: decimal
│ │ │ └── value: 1
│ │ ├── keyword_loc: (1,8)-(1,14) = "rescue"
│ │ └── rescue_expression:
│ │ @ NilNode (location: (1,15)-(1,18))
│ └── operator_loc: (1,4)-(1,5) = "="
├── @ MultiWriteNode (location: (2,0)-(2,23))
│ ├── lefts: (length: 2)
│ │ ├── @ LocalVariableTargetNode (location: (2,0)-(2,3))
│ │ │ ├── name: :foo
│ │ │ └── depth: 0
│ │ └── @ LocalVariableTargetNode (location: (2,5)-(2,8))
│ │ ├── name: :bar
│ │ └── depth: 0
│ ├── rest: ∅
│ ├── rights: (length: 0)
│ ├── lparen_loc: ∅
│ ├── rparen_loc: ∅
│ ├── operator_loc: (2,9)-(2,10) = "="
│ └── value:
│ @ RescueModifierNode (location: (2,11)-(2,23))
│ ├── expression:
│ │ @ IntegerNode (location: (2,11)-(2,12))
│ │ ├── flags: decimal
│ │ └── value: 1
│ ├── keyword_loc: (2,13)-(2,19) = "rescue"
│ └── rescue_expression:
│ @ NilNode (location: (2,20)-(2,23))
├── @ RescueModifierNode (location: (3,0)-(3,21))
│ ├── expression:
│ │ @ LocalVariableWriteNode (location: (3,0)-(3,10))
│ │ ├── name: :foo
│ │ ├── depth: 0
│ │ ├── name_loc: (3,0)-(3,3) = "foo"
│ │ ├── value:
│ │ │ @ ArrayNode (location: (3,6)-(3,10))
│ │ │ ├── flags: ∅
│ │ │ ├── elements: (length: 2)
│ │ │ │ ├── @ IntegerNode (location: (3,6)-(3,7))
│ │ │ │ │ ├── flags: decimal
│ │ │ │ │ └── value: 1
│ │ │ │ └── @ IntegerNode (location: (3,9)-(3,10))
│ │ │ │ ├── flags: decimal
│ │ │ │ └── value: 2
│ │ │ ├── opening_loc: ∅
│ │ │ └── closing_loc: ∅
│ │ └── operator_loc: (3,4)-(3,5) = "="
│ ├── keyword_loc: (3,11)-(3,17) = "rescue"
│ └── rescue_expression:
│ @ NilNode (location: (3,18)-(3,21))
└── @ MultiWriteNode (location: (4,0)-(4,26))
├── lefts: (length: 2)
│ ├── @ LocalVariableTargetNode (location: (4,0)-(4,3))
│ │ ├── name: :foo
│ │ └── depth: 0
│ └── @ LocalVariableTargetNode (location: (4,5)-(4,8))
│ ├── name: :bar
│ └── depth: 0
├── rest: ∅
├── rights: (length: 0)
├── lparen_loc: ∅
├── rparen_loc: ∅
├── operator_loc: (4,9)-(4,10) = "="
└── value:
@ RescueModifierNode (location: (4,11)-(4,26))
├── expression:
│ @ ArrayNode (location: (4,11)-(4,15))
│ ├── flags: ∅
│ ├── elements: (length: 2)
│ │ ├── @ IntegerNode (location: (4,11)-(4,12))
│ │ │ ├── flags: decimal
│ │ │ └── value: 1
│ │ └── @ IntegerNode (location: (4,14)-(4,15))
│ │ ├── flags: decimal
│ │ └── value: 2
│ ├── opening_loc: ∅
│ └── closing_loc: ∅
├── keyword_loc: (4,16)-(4,22) = "rescue"
└── rescue_expression:
@ NilNode (location: (4,23)-(4,26))

0 comments on commit 1a57fee

Please sign in to comment.