[ruby/prism] Fix up it indirect writes

Fixes [Bug #21137]

https://github.com/ruby/prism/commit/ca493e6797
This commit is contained in:
Kevin Newton 2025-02-14 10:10:08 -05:00 committed by git
parent 0cab608d3a
commit ee181d1bb7
3 changed files with 477 additions and 2 deletions

View File

@ -5662,7 +5662,7 @@ pm_lambda_node_create(
*/
static pm_local_variable_and_write_node_t *
pm_local_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value, pm_constant_id_t name, uint32_t depth) {
assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_IT_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
@ -5717,7 +5717,7 @@ pm_local_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *tar
*/
static pm_local_variable_or_write_node_t *
pm_local_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value, pm_constant_id_t name, uint32_t depth) {
assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_IT_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
@ -21218,6 +21218,17 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_node_destroy(parser, node);
return result;
}
case PM_IT_LOCAL_VARIABLE_READ_NODE: {
pm_constant_id_t name = pm_parser_local_add_constant(parser, "it", 2);
parser_lex(parser);
pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0);
parse_target_implicit_parameter(parser, node);
pm_node_destroy(parser, node);
return result;
}
case PM_LOCAL_VARIABLE_READ_NODE: {
if (pm_token_is_numbered_parameter(node->location.start, node->location.end)) {
PM_PARSER_ERR_FORMAT(parser, node->location.start, node->location.end, PM_ERR_PARAMETER_NUMBERED_RESERVED, node->location.start);
@ -21341,6 +21352,17 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_node_destroy(parser, node);
return result;
}
case PM_IT_LOCAL_VARIABLE_READ_NODE: {
pm_constant_id_t name = pm_parser_local_add_constant(parser, "it", 2);
parser_lex(parser);
pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0);
parse_target_implicit_parameter(parser, node);
pm_node_destroy(parser, node);
return result;
}
case PM_LOCAL_VARIABLE_READ_NODE: {
if (pm_token_is_numbered_parameter(node->location.start, node->location.end)) {
PM_PARSER_ERR_FORMAT(parser, node->location.start, node->location.end, PM_ERR_PARAMETER_NUMBERED_RESERVED, node->location.start);
@ -21474,6 +21496,17 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_node_destroy(parser, node);
return result;
}
case PM_IT_LOCAL_VARIABLE_READ_NODE: {
pm_constant_id_t name = pm_parser_local_add_constant(parser, "it", 2);
parser_lex(parser);
pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0);
parse_target_implicit_parameter(parser, node);
pm_node_destroy(parser, node);
return result;
}
case PM_LOCAL_VARIABLE_READ_NODE: {
if (pm_token_is_numbered_parameter(node->location.start, node->location.end)) {
PM_PARSER_ERR_FORMAT(parser, node->location.start, node->location.end, PM_ERR_PARAMETER_NUMBERED_RESERVED, node->location.start);

View File

@ -0,0 +1,23 @@
tap { it += 1 }
tap { it ||= 1 }
tap { it &&= 1 }
tap { it; it += 1 }
tap { it; it ||= 1 }
tap { it; it &&= 1 }
tap { it += 1; it }
tap { it ||= 1; it }
tap { it &&= 1; it }
tap { it; it += 1; it }
tap { it; it ||= 1; it }
tap { it; it &&= 1; it }

View File

@ -0,0 +1,419 @@
@ ProgramNode (location: (1,0)-(23,24))
├── flags: ∅
├── locals: []
└── statements:
@ StatementsNode (location: (1,0)-(23,24))
├── flags: ∅
└── body: (length: 12)
├── @ CallNode (location: (1,0)-(1,15))
│ ├── flags: newline, ignore_visibility
│ ├── receiver: ∅
│ ├── call_operator_loc: ∅
│ ├── name: :tap
│ ├── message_loc: (1,0)-(1,3) = "tap"
│ ├── opening_loc: ∅
│ ├── arguments: ∅
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (1,4)-(1,15))
│ ├── flags: ∅
│ ├── locals: [:it]
│ ├── parameters: ∅
│ ├── body:
│ │ @ StatementsNode (location: (1,6)-(1,13))
│ │ ├── flags: ∅
│ │ └── body: (length: 1)
│ │ └── @ LocalVariableOperatorWriteNode (location: (1,6)-(1,13))
│ │ ├── flags: newline
│ │ ├── name_loc: (1,6)-(1,8) = "it"
│ │ ├── binary_operator_loc: (1,9)-(1,11) = "+="
│ │ ├── value:
│ │ │ @ IntegerNode (location: (1,12)-(1,13))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 1
│ │ ├── name: :it
│ │ ├── binary_operator: :+
│ │ └── depth: 0
│ ├── opening_loc: (1,4)-(1,5) = "{"
│ └── closing_loc: (1,14)-(1,15) = "}"
├── @ CallNode (location: (3,0)-(3,16))
│ ├── flags: newline, ignore_visibility
│ ├── receiver: ∅
│ ├── call_operator_loc: ∅
│ ├── name: :tap
│ ├── message_loc: (3,0)-(3,3) = "tap"
│ ├── opening_loc: ∅
│ ├── arguments: ∅
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (3,4)-(3,16))
│ ├── flags: ∅
│ ├── locals: [:it]
│ ├── parameters: ∅
│ ├── body:
│ │ @ StatementsNode (location: (3,6)-(3,14))
│ │ ├── flags: ∅
│ │ └── body: (length: 1)
│ │ └── @ LocalVariableOrWriteNode (location: (3,6)-(3,14))
│ │ ├── flags: newline
│ │ ├── name_loc: (3,6)-(3,8) = "it"
│ │ ├── operator_loc: (3,9)-(3,12) = "||="
│ │ ├── value:
│ │ │ @ IntegerNode (location: (3,13)-(3,14))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 1
│ │ ├── name: :it
│ │ └── depth: 0
│ ├── opening_loc: (3,4)-(3,5) = "{"
│ └── closing_loc: (3,15)-(3,16) = "}"
├── @ CallNode (location: (5,0)-(5,16))
│ ├── flags: newline, ignore_visibility
│ ├── receiver: ∅
│ ├── call_operator_loc: ∅
│ ├── name: :tap
│ ├── message_loc: (5,0)-(5,3) = "tap"
│ ├── opening_loc: ∅
│ ├── arguments: ∅
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (5,4)-(5,16))
│ ├── flags: ∅
│ ├── locals: [:it]
│ ├── parameters: ∅
│ ├── body:
│ │ @ StatementsNode (location: (5,6)-(5,14))
│ │ ├── flags: ∅
│ │ └── body: (length: 1)
│ │ └── @ LocalVariableAndWriteNode (location: (5,6)-(5,14))
│ │ ├── flags: newline
│ │ ├── name_loc: (5,6)-(5,8) = "it"
│ │ ├── operator_loc: (5,9)-(5,12) = "&&="
│ │ ├── value:
│ │ │ @ IntegerNode (location: (5,13)-(5,14))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 1
│ │ ├── name: :it
│ │ └── depth: 0
│ ├── opening_loc: (5,4)-(5,5) = "{"
│ └── closing_loc: (5,15)-(5,16) = "}"
├── @ CallNode (location: (7,0)-(7,19))
│ ├── flags: newline, ignore_visibility
│ ├── receiver: ∅
│ ├── call_operator_loc: ∅
│ ├── name: :tap
│ ├── message_loc: (7,0)-(7,3) = "tap"
│ ├── opening_loc: ∅
│ ├── arguments: ∅
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (7,4)-(7,19))
│ ├── flags: ∅
│ ├── locals: [:it]
│ ├── parameters:
│ │ @ ItParametersNode (location: (7,4)-(7,19))
│ │ └── flags: ∅
│ ├── body:
│ │ @ StatementsNode (location: (7,6)-(7,17))
│ │ ├── flags: ∅
│ │ └── body: (length: 2)
│ │ ├── @ ItLocalVariableReadNode (location: (7,6)-(7,8))
│ │ │ └── flags: newline
│ │ └── @ LocalVariableOperatorWriteNode (location: (7,10)-(7,17))
│ │ ├── flags: newline
│ │ ├── name_loc: (7,10)-(7,12) = "it"
│ │ ├── binary_operator_loc: (7,13)-(7,15) = "+="
│ │ ├── value:
│ │ │ @ IntegerNode (location: (7,16)-(7,17))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 1
│ │ ├── name: :it
│ │ ├── binary_operator: :+
│ │ └── depth: 0
│ ├── opening_loc: (7,4)-(7,5) = "{"
│ └── closing_loc: (7,18)-(7,19) = "}"
├── @ CallNode (location: (9,0)-(9,20))
│ ├── flags: newline, ignore_visibility
│ ├── receiver: ∅
│ ├── call_operator_loc: ∅
│ ├── name: :tap
│ ├── message_loc: (9,0)-(9,3) = "tap"
│ ├── opening_loc: ∅
│ ├── arguments: ∅
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (9,4)-(9,20))
│ ├── flags: ∅
│ ├── locals: [:it]
│ ├── parameters:
│ │ @ ItParametersNode (location: (9,4)-(9,20))
│ │ └── flags: ∅
│ ├── body:
│ │ @ StatementsNode (location: (9,6)-(9,18))
│ │ ├── flags: ∅
│ │ └── body: (length: 2)
│ │ ├── @ ItLocalVariableReadNode (location: (9,6)-(9,8))
│ │ │ └── flags: newline
│ │ └── @ LocalVariableOrWriteNode (location: (9,10)-(9,18))
│ │ ├── flags: newline
│ │ ├── name_loc: (9,10)-(9,12) = "it"
│ │ ├── operator_loc: (9,13)-(9,16) = "||="
│ │ ├── value:
│ │ │ @ IntegerNode (location: (9,17)-(9,18))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 1
│ │ ├── name: :it
│ │ └── depth: 0
│ ├── opening_loc: (9,4)-(9,5) = "{"
│ └── closing_loc: (9,19)-(9,20) = "}"
├── @ CallNode (location: (11,0)-(11,20))
│ ├── flags: newline, ignore_visibility
│ ├── receiver: ∅
│ ├── call_operator_loc: ∅
│ ├── name: :tap
│ ├── message_loc: (11,0)-(11,3) = "tap"
│ ├── opening_loc: ∅
│ ├── arguments: ∅
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (11,4)-(11,20))
│ ├── flags: ∅
│ ├── locals: [:it]
│ ├── parameters:
│ │ @ ItParametersNode (location: (11,4)-(11,20))
│ │ └── flags: ∅
│ ├── body:
│ │ @ StatementsNode (location: (11,6)-(11,18))
│ │ ├── flags: ∅
│ │ └── body: (length: 2)
│ │ ├── @ ItLocalVariableReadNode (location: (11,6)-(11,8))
│ │ │ └── flags: newline
│ │ └── @ LocalVariableAndWriteNode (location: (11,10)-(11,18))
│ │ ├── flags: newline
│ │ ├── name_loc: (11,10)-(11,12) = "it"
│ │ ├── operator_loc: (11,13)-(11,16) = "&&="
│ │ ├── value:
│ │ │ @ IntegerNode (location: (11,17)-(11,18))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 1
│ │ ├── name: :it
│ │ └── depth: 0
│ ├── opening_loc: (11,4)-(11,5) = "{"
│ └── closing_loc: (11,19)-(11,20) = "}"
├── @ CallNode (location: (13,0)-(13,19))
│ ├── flags: newline, ignore_visibility
│ ├── receiver: ∅
│ ├── call_operator_loc: ∅
│ ├── name: :tap
│ ├── message_loc: (13,0)-(13,3) = "tap"
│ ├── opening_loc: ∅
│ ├── arguments: ∅
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (13,4)-(13,19))
│ ├── flags: ∅
│ ├── locals: [:it]
│ ├── parameters: ∅
│ ├── body:
│ │ @ StatementsNode (location: (13,6)-(13,17))
│ │ ├── flags: ∅
│ │ └── body: (length: 2)
│ │ ├── @ LocalVariableOperatorWriteNode (location: (13,6)-(13,13))
│ │ │ ├── flags: newline
│ │ │ ├── name_loc: (13,6)-(13,8) = "it"
│ │ │ ├── binary_operator_loc: (13,9)-(13,11) = "+="
│ │ │ ├── value:
│ │ │ │ @ IntegerNode (location: (13,12)-(13,13))
│ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ └── value: 1
│ │ │ ├── name: :it
│ │ │ ├── binary_operator: :+
│ │ │ └── depth: 0
│ │ └── @ LocalVariableReadNode (location: (13,15)-(13,17))
│ │ ├── flags: newline
│ │ ├── name: :it
│ │ └── depth: 0
│ ├── opening_loc: (13,4)-(13,5) = "{"
│ └── closing_loc: (13,18)-(13,19) = "}"
├── @ CallNode (location: (15,0)-(15,20))
│ ├── flags: newline, ignore_visibility
│ ├── receiver: ∅
│ ├── call_operator_loc: ∅
│ ├── name: :tap
│ ├── message_loc: (15,0)-(15,3) = "tap"
│ ├── opening_loc: ∅
│ ├── arguments: ∅
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (15,4)-(15,20))
│ ├── flags: ∅
│ ├── locals: [:it]
│ ├── parameters: ∅
│ ├── body:
│ │ @ StatementsNode (location: (15,6)-(15,18))
│ │ ├── flags: ∅
│ │ └── body: (length: 2)
│ │ ├── @ LocalVariableOrWriteNode (location: (15,6)-(15,14))
│ │ │ ├── flags: newline
│ │ │ ├── name_loc: (15,6)-(15,8) = "it"
│ │ │ ├── operator_loc: (15,9)-(15,12) = "||="
│ │ │ ├── value:
│ │ │ │ @ IntegerNode (location: (15,13)-(15,14))
│ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ └── value: 1
│ │ │ ├── name: :it
│ │ │ └── depth: 0
│ │ └── @ LocalVariableReadNode (location: (15,16)-(15,18))
│ │ ├── flags: newline
│ │ ├── name: :it
│ │ └── depth: 0
│ ├── opening_loc: (15,4)-(15,5) = "{"
│ └── closing_loc: (15,19)-(15,20) = "}"
├── @ CallNode (location: (17,0)-(17,20))
│ ├── flags: newline, ignore_visibility
│ ├── receiver: ∅
│ ├── call_operator_loc: ∅
│ ├── name: :tap
│ ├── message_loc: (17,0)-(17,3) = "tap"
│ ├── opening_loc: ∅
│ ├── arguments: ∅
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (17,4)-(17,20))
│ ├── flags: ∅
│ ├── locals: [:it]
│ ├── parameters: ∅
│ ├── body:
│ │ @ StatementsNode (location: (17,6)-(17,18))
│ │ ├── flags: ∅
│ │ └── body: (length: 2)
│ │ ├── @ LocalVariableAndWriteNode (location: (17,6)-(17,14))
│ │ │ ├── flags: newline
│ │ │ ├── name_loc: (17,6)-(17,8) = "it"
│ │ │ ├── operator_loc: (17,9)-(17,12) = "&&="
│ │ │ ├── value:
│ │ │ │ @ IntegerNode (location: (17,13)-(17,14))
│ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ └── value: 1
│ │ │ ├── name: :it
│ │ │ └── depth: 0
│ │ └── @ LocalVariableReadNode (location: (17,16)-(17,18))
│ │ ├── flags: newline
│ │ ├── name: :it
│ │ └── depth: 0
│ ├── opening_loc: (17,4)-(17,5) = "{"
│ └── closing_loc: (17,19)-(17,20) = "}"
├── @ CallNode (location: (19,0)-(19,23))
│ ├── flags: newline, ignore_visibility
│ ├── receiver: ∅
│ ├── call_operator_loc: ∅
│ ├── name: :tap
│ ├── message_loc: (19,0)-(19,3) = "tap"
│ ├── opening_loc: ∅
│ ├── arguments: ∅
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (19,4)-(19,23))
│ ├── flags: ∅
│ ├── locals: [:it]
│ ├── parameters:
│ │ @ ItParametersNode (location: (19,4)-(19,23))
│ │ └── flags: ∅
│ ├── body:
│ │ @ StatementsNode (location: (19,6)-(19,21))
│ │ ├── flags: ∅
│ │ └── body: (length: 3)
│ │ ├── @ ItLocalVariableReadNode (location: (19,6)-(19,8))
│ │ │ └── flags: newline
│ │ ├── @ LocalVariableOperatorWriteNode (location: (19,10)-(19,17))
│ │ │ ├── flags: newline
│ │ │ ├── name_loc: (19,10)-(19,12) = "it"
│ │ │ ├── binary_operator_loc: (19,13)-(19,15) = "+="
│ │ │ ├── value:
│ │ │ │ @ IntegerNode (location: (19,16)-(19,17))
│ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ └── value: 1
│ │ │ ├── name: :it
│ │ │ ├── binary_operator: :+
│ │ │ └── depth: 0
│ │ └── @ LocalVariableReadNode (location: (19,19)-(19,21))
│ │ ├── flags: newline
│ │ ├── name: :it
│ │ └── depth: 0
│ ├── opening_loc: (19,4)-(19,5) = "{"
│ └── closing_loc: (19,22)-(19,23) = "}"
├── @ CallNode (location: (21,0)-(21,24))
│ ├── flags: newline, ignore_visibility
│ ├── receiver: ∅
│ ├── call_operator_loc: ∅
│ ├── name: :tap
│ ├── message_loc: (21,0)-(21,3) = "tap"
│ ├── opening_loc: ∅
│ ├── arguments: ∅
│ ├── closing_loc: ∅
│ └── block:
│ @ BlockNode (location: (21,4)-(21,24))
│ ├── flags: ∅
│ ├── locals: [:it]
│ ├── parameters:
│ │ @ ItParametersNode (location: (21,4)-(21,24))
│ │ └── flags: ∅
│ ├── body:
│ │ @ StatementsNode (location: (21,6)-(21,22))
│ │ ├── flags: ∅
│ │ └── body: (length: 3)
│ │ ├── @ ItLocalVariableReadNode (location: (21,6)-(21,8))
│ │ │ └── flags: newline
│ │ ├── @ LocalVariableOrWriteNode (location: (21,10)-(21,18))
│ │ │ ├── flags: newline
│ │ │ ├── name_loc: (21,10)-(21,12) = "it"
│ │ │ ├── operator_loc: (21,13)-(21,16) = "||="
│ │ │ ├── value:
│ │ │ │ @ IntegerNode (location: (21,17)-(21,18))
│ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ └── value: 1
│ │ │ ├── name: :it
│ │ │ └── depth: 0
│ │ └── @ LocalVariableReadNode (location: (21,20)-(21,22))
│ │ ├── flags: newline
│ │ ├── name: :it
│ │ └── depth: 0
│ ├── opening_loc: (21,4)-(21,5) = "{"
│ └── closing_loc: (21,23)-(21,24) = "}"
└── @ CallNode (location: (23,0)-(23,24))
├── flags: newline, ignore_visibility
├── receiver: ∅
├── call_operator_loc: ∅
├── name: :tap
├── message_loc: (23,0)-(23,3) = "tap"
├── opening_loc: ∅
├── arguments: ∅
├── closing_loc: ∅
└── block:
@ BlockNode (location: (23,4)-(23,24))
├── flags: ∅
├── locals: [:it]
├── parameters:
│ @ ItParametersNode (location: (23,4)-(23,24))
│ └── flags: ∅
├── body:
│ @ StatementsNode (location: (23,6)-(23,22))
│ ├── flags: ∅
│ └── body: (length: 3)
│ ├── @ ItLocalVariableReadNode (location: (23,6)-(23,8))
│ │ └── flags: newline
│ ├── @ LocalVariableAndWriteNode (location: (23,10)-(23,18))
│ │ ├── flags: newline
│ │ ├── name_loc: (23,10)-(23,12) = "it"
│ │ ├── operator_loc: (23,13)-(23,16) = "&&="
│ │ ├── value:
│ │ │ @ IntegerNode (location: (23,17)-(23,18))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 1
│ │ ├── name: :it
│ │ └── depth: 0
│ └── @ LocalVariableReadNode (location: (23,20)-(23,22))
│ ├── flags: newline
│ ├── name: :it
│ └── depth: 0
├── opening_loc: (23,4)-(23,5) = "{"
└── closing_loc: (23,23)-(23,24) = "}"