summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTSUYUSATO Kitsune <[email protected]>2023-11-30 17:42:35 +0900
committergit <[email protected]>2023-12-05 15:16:40 +0000
commitdcd75fd49dd879f4931b1c5b1bd65990a92badb5 (patch)
tree9b51df22a507f4270bf668b8ae2af957d37cb92b
parent6b9622ebdfc5ef12ee379cd1f0818b0188e1e068 (diff)
[ruby/prism] Fix to parse command-style method calls more correctly
Fix https://github.com/ruby/prism/pull/1468 Fix https://github.com/ruby/prism/pull/1575 To decide command-style method calls are allowed, this introduce a new parameter `accepts_command_call` to `parse_expression` and some functions. Although one think this can be solved by operator precedence, it is hard or impossible, because the precedence of command-style calls is skewed (e.g. `! bar 1 ` is accepted, but `foo = ! bar 1` is rejected.) One of the most complex examples is that: (1) even though `foo = bar = baz 1` and `foo, bar = baz 1` is accepted, (2) `foo, bar = baz = fuzz 1` is rejected. To implement this behavior, this introduces a new binding power `PM_BINDING_POWER_MULTI_ASSIGNMENT` and uses it for distinguish which single assignments or multi assignments at their RHS. https://github.com/ruby/prism/commit/d4dd49ca81
-rw-r--r--prism/prism.c362
-rw-r--r--test/prism/errors_test.rb36
-rw-r--r--test/prism/fixtures/command_method_call.txt31
-rw-r--r--test/prism/snapshots/command_method_call.txt508
4 files changed, 781 insertions, 156 deletions
diff --git a/prism/prism.c b/prism/prism.c
index 15f99445fb..63595700cd 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -10042,32 +10042,33 @@ parser_lex(pm_parser_t *parser) {
* specify their associativity by adding or subtracting one.
*/
typedef enum {
- PM_BINDING_POWER_UNSET = 0, // used to indicate this token cannot be used as an infix operator
- PM_BINDING_POWER_STATEMENT = 2,
- PM_BINDING_POWER_MODIFIER = 4, // if unless until while
- PM_BINDING_POWER_MODIFIER_RESCUE = 6, // rescue
- PM_BINDING_POWER_COMPOSITION = 8, // and or
- PM_BINDING_POWER_NOT = 10, // not
- PM_BINDING_POWER_MATCH = 12, // => in
- PM_BINDING_POWER_DEFINED = 14, // defined?
- PM_BINDING_POWER_ASSIGNMENT = 16, // = += -= *= /= %= &= |= ^= &&= ||= <<= >>= **=
- PM_BINDING_POWER_TERNARY = 18, // ?:
- PM_BINDING_POWER_RANGE = 20, // .. ...
- PM_BINDING_POWER_LOGICAL_OR = 22, // ||
- PM_BINDING_POWER_LOGICAL_AND = 24, // &&
- PM_BINDING_POWER_EQUALITY = 26, // <=> == === != =~ !~
- PM_BINDING_POWER_COMPARISON = 28, // > >= < <=
- PM_BINDING_POWER_BITWISE_OR = 30, // | ^
- PM_BINDING_POWER_BITWISE_AND = 32, // &
- PM_BINDING_POWER_SHIFT = 34, // << >>
- PM_BINDING_POWER_TERM = 36, // + -
- PM_BINDING_POWER_FACTOR = 38, // * / %
- PM_BINDING_POWER_UMINUS = 40, // -@
- PM_BINDING_POWER_EXPONENT = 42, // **
- PM_BINDING_POWER_UNARY = 44, // ! ~ +@
- PM_BINDING_POWER_INDEX = 46, // [] []=
- PM_BINDING_POWER_CALL = 48, // :: .
- PM_BINDING_POWER_MAX = 50
+ PM_BINDING_POWER_UNSET = 0, // used to indicate this token cannot be used as an infix operator
+ PM_BINDING_POWER_STATEMENT = 2,
+ PM_BINDING_POWER_MODIFIER = 4, // if unless until while
+ PM_BINDING_POWER_MODIFIER_RESCUE = 6, // rescue
+ PM_BINDING_POWER_COMPOSITION = 8, // and or
+ PM_BINDING_POWER_NOT = 10, // not
+ PM_BINDING_POWER_MATCH = 12, // => in
+ PM_BINDING_POWER_DEFINED = 14, // defined?
+ PM_BINDING_POWER_MULTI_ASSIGNMENT = 16, // =
+ PM_BINDING_POWER_ASSIGNMENT = 18, // = += -= *= /= %= &= |= ^= &&= ||= <<= >>= **=
+ PM_BINDING_POWER_TERNARY = 20, // ?:
+ PM_BINDING_POWER_RANGE = 22, // .. ...
+ PM_BINDING_POWER_LOGICAL_OR = 24, // ||
+ PM_BINDING_POWER_LOGICAL_AND = 26, // &&
+ PM_BINDING_POWER_EQUALITY = 28, // <=> == === != =~ !~
+ PM_BINDING_POWER_COMPARISON = 30, // > >= < <=
+ PM_BINDING_POWER_BITWISE_OR = 32, // | ^
+ PM_BINDING_POWER_BITWISE_AND = 34, // &
+ PM_BINDING_POWER_SHIFT = 36, // << >>
+ PM_BINDING_POWER_TERM = 38, // + -
+ PM_BINDING_POWER_FACTOR = 40, // * / %
+ PM_BINDING_POWER_UMINUS = 42, // -@
+ PM_BINDING_POWER_EXPONENT = 44, // **
+ PM_BINDING_POWER_UNARY = 46, // ! ~ +@
+ PM_BINDING_POWER_INDEX = 48, // [] []=
+ PM_BINDING_POWER_CALL = 50, // :: .
+ PM_BINDING_POWER_MAX = 52
} pm_binding_power_t;
/**
@@ -10365,14 +10366,14 @@ expect3(pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_to
}
static pm_node_t *
-parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id);
+parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id, bool accepts_comamnd_call);
/**
* This is a wrapper of parse_expression, which also checks whether the resulting node is value expression.
*/
static pm_node_t *
-parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id) {
- pm_node_t *node = parse_expression(parser, binding_power, diag_id);
+parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id, bool accepts_command_call) {
+ pm_node_t *node = parse_expression(parser, binding_power, diag_id, accepts_command_call);
pm_assert_value_expression(parser, node);
return node;
}
@@ -10457,14 +10458,14 @@ token_begins_expression_p(pm_token_type_t type) {
* prefixed by the * operator.
*/
static pm_node_t *
-parse_starred_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id) {
+parse_starred_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id, bool accepts_command_call) {
if (accept1(parser, PM_TOKEN_USTAR)) {
pm_token_t operator = parser->previous;
- pm_node_t *expression = parse_value_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR);
+ pm_node_t *expression = parse_value_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, false);
return (pm_node_t *) pm_splat_node_create(parser, &operator, expression);
}
- return parse_value_expression(parser, binding_power, diag_id);
+ return parse_value_expression(parser, binding_power, diag_id, accepts_command_call);
}
/**
@@ -10814,7 +10815,7 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b
pm_node_t *name = NULL;
if (token_begins_expression_p(parser->current.type)) {
- name = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR);
+ name = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, false);
name = parse_target(parser, name);
}
@@ -10822,7 +10823,7 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b
pm_multi_target_node_targets_append(parser, result, splat);
has_rest = true;
} else if (token_begins_expression_p(parser->current.type)) {
- pm_node_t *target = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA);
+ pm_node_t *target = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, false);
target = parse_target(parser, target);
pm_multi_target_node_targets_append(parser, result, target);
@@ -10873,7 +10874,7 @@ parse_statements(pm_parser_t *parser, pm_context_t context) {
context_push(parser, context);
while (true) {
- pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_CANNOT_PARSE_EXPRESSION);
+ pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_CANNOT_PARSE_EXPRESSION, true);
pm_statements_node_body_append(statements, node);
// If we're recovering from a syntax error, then we need to stop parsing the
@@ -10944,7 +10945,7 @@ parse_assocs(pm_parser_t *parser, pm_node_t *node) {
pm_node_t *value = NULL;
if (token_begins_expression_p(parser->current.type)) {
- value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH);
+ value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, false);
} else if (pm_parser_local_depth(parser, &operator) == -1) {
pm_parser_err_token(parser, &operator, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH);
}
@@ -10962,7 +10963,7 @@ parse_assocs(pm_parser_t *parser, pm_node_t *node) {
pm_node_t *value = NULL;
if (token_begins_expression_p(parser->current.type)) {
- value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_EXPRESSION_AFTER_LABEL);
+ value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, false);
} else {
if (parser->encoding.isupper_char(label.start, (label.end - 1) - label.start)) {
pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.start, .end = label.end - 1 };
@@ -10986,7 +10987,7 @@ parse_assocs(pm_parser_t *parser, pm_node_t *node) {
break;
}
default: {
- pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_KEY);
+ pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_KEY, false);
pm_token_t operator;
if (pm_symbol_node_label_p(key)) {
@@ -10996,7 +10997,7 @@ parse_assocs(pm_parser_t *parser, pm_node_t *node) {
operator = parser->previous;
}
- pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_VALUE);
+ pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_VALUE, false);
element = (pm_node_t *) pm_assoc_node_create(parser, key, &operator, value);
break;
}
@@ -11097,7 +11098,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
pm_node_t *expression = NULL;
if (token_begins_expression_p(parser->current.type)) {
- expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_ARGUMENT);
+ expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_ARGUMENT, false);
} else {
if (pm_parser_local_depth(parser, &operator) == -1) {
// A block forwarding in a method having `...` parameter (e.g. `def foo(...); bar(&); end`) is available.
@@ -11129,7 +11130,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
argument = (pm_node_t *) pm_splat_node_create(parser, &operator, NULL);
} else {
- pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT);
+ pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, false);
if (parsed_bare_hash) {
pm_parser_err(parser, operator.start, expression->location.end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
@@ -11149,7 +11150,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
// If the token begins an expression then this ... was not actually
// argument forwarding but was instead a range.
pm_token_t operator = parser->previous;
- pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+ pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, false);
argument = (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right);
} else {
if (pm_parser_local_depth(parser, &parser->previous) == -1) {
@@ -11169,7 +11170,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
/* fallthrough */
default: {
if (argument == NULL) {
- argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_ARGUMENT);
+ argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_ARGUMENT, !parsed_first_argument);
}
bool contains_keyword_splat = false;
@@ -11188,7 +11189,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
pm_keyword_hash_node_t *bare_hash = pm_keyword_hash_node_create(parser);
// Finish parsing the one we are part way through
- pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_VALUE);
+ pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_VALUE, false);
argument = (pm_node_t *) pm_assoc_node_create(parser, argument, &operator, value);
pm_keyword_hash_node_elements_append(bare_hash, argument);
@@ -11499,7 +11500,7 @@ parse_parameters(
context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
pm_constant_id_t old_param_name = parser->current_param_name;
parser->current_param_name = pm_parser_constant_id_token(parser, &name);
- pm_node_t *value = parse_value_expression(parser, binding_power, PM_ERR_PARAMETER_NO_DEFAULT);
+ pm_node_t *value = parse_value_expression(parser, binding_power, PM_ERR_PARAMETER_NO_DEFAULT, false);
pm_optional_parameter_node_t *param = pm_optional_parameter_node_create(parser, &name, &operator, value);
pm_parameters_node_optionals_append(params, param);
@@ -11562,7 +11563,7 @@ parse_parameters(
context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
pm_constant_id_t old_param_name = parser->current_param_name;
parser->current_param_name = pm_parser_constant_id_token(parser, &local);
- pm_node_t *value = parse_value_expression(parser, binding_power, PM_ERR_PARAMETER_NO_DEFAULT_KW);
+ pm_node_t *value = parse_value_expression(parser, binding_power, PM_ERR_PARAMETER_NO_DEFAULT_KW, false);
parser->current_param_name = old_param_name;
context_pop(parser);
param = (pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
@@ -11710,7 +11711,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, bool def_p) {
parser_lex(parser);
pm_rescue_node_operator_set(rescue, &parser->previous);
- pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_RESCUE_VARIABLE);
+ pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_RESCUE_VARIABLE, false);
reference = parse_target(parser, reference);
pm_rescue_node_reference_set(rescue, reference);
@@ -11728,7 +11729,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, bool def_p) {
// we'll attempt to parse it here and any others delimited by commas.
do {
- pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_RESCUE_EXPRESSION);
+ pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_RESCUE_EXPRESSION, false);
pm_rescue_node_exceptions_append(rescue, expression);
// If we hit a newline, then this is the end of the rescue expression. We
@@ -11740,7 +11741,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, bool def_p) {
if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
pm_rescue_node_operator_set(rescue, &parser->previous);
- pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_RESCUE_VARIABLE);
+ pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_RESCUE_VARIABLE, false);
reference = parse_target(parser, reference);
pm_rescue_node_reference_set(rescue, reference);
@@ -11963,7 +11964,7 @@ parse_block(pm_parser_t *parser) {
* arguments, or blocks).
*/
static bool
-parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_block) {
+parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_block, bool accepts_command_call) {
bool found = false;
if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
@@ -11980,7 +11981,7 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept
arguments->closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
}
- } else if ((token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR, PM_TOKEN_UAMPERSAND)) && !match1(parser, PM_TOKEN_BRACE_LEFT)) {
+ } else if (accepts_command_call && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR, PM_TOKEN_UAMPERSAND)) && !match1(parser, PM_TOKEN_BRACE_LEFT)) {
found |= true;
pm_accepts_block_stack_push(parser, false);
@@ -12035,7 +12036,7 @@ static inline pm_node_t *
parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context, pm_token_t *then_keyword) {
context_push(parser, PM_CONTEXT_PREDICATE);
pm_diagnostic_id_t error_id = context == PM_CONTEXT_IF ? PM_ERR_CONDITIONAL_IF_PREDICATE : PM_ERR_CONDITIONAL_UNLESS_PREDICATE;
- pm_node_t *predicate = parse_value_expression(parser, binding_power, error_id);
+ pm_node_t *predicate = parse_value_expression(parser, binding_power, error_id, true);
// Predicates are closed by a term, a "then", or a term and then a "then".
bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
@@ -13061,7 +13062,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
first_assoc = parse_pattern_keyword_rest(parser);
break;
case PM_TOKEN_STRING_BEGIN: {
- pm_node_t *key = parse_expression(parser, PM_BINDING_POWER_MAX, PM_ERR_PATTERN_HASH_KEY);
+ pm_node_t *key = parse_expression(parser, PM_BINDING_POWER_MAX, PM_ERR_PATTERN_HASH_KEY, false);
pm_token_t operator = not_provided(parser);
if (!pm_symbol_node_label_p(key)) {
@@ -13108,7 +13109,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
// expression as the right side of the range.
switch (parser->current.type) {
case PM_CASE_PRIMITIVE: {
- pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
+ pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, false);
return (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right);
}
default: {
@@ -13119,7 +13120,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
}
}
case PM_CASE_PRIMITIVE: {
- pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX, diag_id);
+ pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX, diag_id, false);
// Now that we have a primitive, we need to check if it's part of a range.
if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
@@ -13130,7 +13131,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
// node. Otherwise, we'll create an endless range.
switch (parser->current.type) {
case PM_CASE_PRIMITIVE: {
- pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
+ pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, false);
return (pm_node_t *) pm_range_node_create(parser, node, &operator, right);
}
default:
@@ -13190,7 +13191,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
pm_token_t lparen = parser->current;
parser_lex(parser);
- pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
+ pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, true);
parser->pattern_matching_newlines = previous_pattern_matching_newlines;
accept1(parser, PM_TOKEN_NEWLINE);
@@ -13629,7 +13630,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) {
* Parse an expression that begins with the previous node that we just lexed.
*/
static inline pm_node_t *
-parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
+parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call) {
switch (parser->current.type) {
case PM_TOKEN_BRACKET_LEFT_ARRAY: {
parser_lex(parser);
@@ -13665,7 +13666,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
pm_parser_err_token(parser, &operator, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
}
} else {
- expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR);
+ expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, false);
}
element = (pm_node_t *) pm_splat_node_create(parser, &operator, expression);
@@ -13683,7 +13684,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
parsed_bare_hash = true;
} else {
- element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_ARRAY_EXPRESSION);
+ element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_ARRAY_EXPRESSION, false);
if (pm_symbol_node_label_p(element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
if (parsed_bare_hash) {
@@ -13699,7 +13700,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
operator = not_provided(parser);
}
- pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_VALUE);
+ pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_VALUE, false);
pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, element, &operator, value);
pm_keyword_hash_node_elements_append(hash, assoc);
@@ -13740,7 +13741,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
// of statements within the parentheses.
pm_accepts_block_stack_push(parser, true);
context_push(parser, PM_CONTEXT_PARENS);
- pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_CANNOT_PARSE_EXPRESSION);
+ pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_CANNOT_PARSE_EXPRESSION, true);
context_pop(parser);
// Determine if this statement is followed by a terminator. In the
@@ -13816,7 +13817,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
// Parse each statement within the parentheses.
while (true) {
- pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_CANNOT_PARSE_EXPRESSION);
+ pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_CANNOT_PARSE_EXPRESSION, true);
pm_statements_node_body_append(statements, node);
// If we're recovering from a syntax error, then we need to stop
@@ -13906,11 +13907,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
// fact a method call, not a constant read.
if (
match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
- (binding_power <= PM_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
+ (accepts_command_call && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
(pm_accepts_block_stack_p(parser) && match2(parser, PM_TOKEN_KEYWORD_DO, PM_TOKEN_BRACE_LEFT))
) {
pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true);
+ parse_arguments_list(parser, &arguments, true, accepts_command_call);
return (pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments);
}
@@ -13944,7 +13945,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
pm_token_t operator = parser->current;
parser_lex(parser);
- pm_node_t *right = parse_expression(parser, pm_binding_powers[operator.type].left, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+ pm_node_t *right = parse_expression(parser, pm_binding_powers[operator.type].left, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, false);
return (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right);
}
case PM_TOKEN_FLOAT:
@@ -14003,7 +14004,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
pm_call_node_t *call = (pm_call_node_t *) node;
pm_arguments_t arguments = { 0 };
- if (parse_arguments_list(parser, &arguments, true)) {
+ if (parse_arguments_list(parser, &arguments, true, accepts_command_call)) {
// Since we found arguments, we need to turn off the
// variable call bit in the flags.
call->base.flags &= (pm_node_flags_t) ~PM_CALL_NODE_FLAGS_VARIABLE_CALL;
@@ -14030,11 +14031,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
// can still be a method call if it is followed by arguments or
// a block, so we need to check for that here.
if (
- (binding_power <= PM_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
+ (accepts_command_call && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
(pm_accepts_block_stack_p(parser) && match2(parser, PM_TOKEN_KEYWORD_DO, PM_TOKEN_BRACE_LEFT))
) {
pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true);
+ parse_arguments_list(parser, &arguments, true, accepts_command_call);
pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
pm_node_destroy(parser, node);
@@ -14250,7 +14251,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
} else if (!token_begins_expression_p(parser->current.type)) {
predicate = NULL;
} else {
- predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CASE_EXPRESSION_AFTER_CASE);
+ predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CASE_EXPRESSION_AFTER_CASE, true);
while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
}
@@ -14277,14 +14278,14 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
do {
if (accept1(parser, PM_TOKEN_USTAR)) {
pm_token_t operator = parser->previous;
- pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR);
+ pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, false);
pm_splat_node_t *splat_node = pm_splat_node_create(parser, &operator, expression);
pm_when_node_conditions_append(when_node, (pm_node_t *) splat_node);
if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE)) break;
} else {
- pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_CASE_EXPRESSION_AFTER_WHEN);
+ pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, false);
pm_when_node_conditions_append(when_node, condition);
if (PM_NODE_TYPE_P(condition, PM_MISSING_NODE)) break;
@@ -14341,11 +14342,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
// for guard clauses in the form of `if` or `unless` statements.
if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
pm_token_t keyword = parser->previous;
- pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_CONDITIONAL_IF_PREDICATE);
+ pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_CONDITIONAL_IF_PREDICATE, true);
pattern = (pm_node_t *) pm_if_node_modifier_create(parser, pattern, &keyword, predicate);
} else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
pm_token_t keyword = parser->previous;
- pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_CONDITIONAL_UNLESS_PREDICATE);
+ pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, true);
pattern = (pm_node_t *) pm_unless_node_modifier_create(parser, pattern, &keyword, predicate);
}
@@ -14504,7 +14505,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
pm_token_t keyword = parser->previous;
pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true);
+ parse_arguments_list(parser, &arguments, true, accepts_command_call);
if (
arguments.opening_loc.start == NULL &&
@@ -14521,7 +14522,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
pm_token_t keyword = parser->previous;
pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, false);
+ parse_arguments_list(parser, &arguments, false, accepts_command_call);
return (pm_node_t *) pm_yield_node_create(parser, &keyword, &arguments.opening_loc, arguments.arguments, &arguments.closing_loc);
}
@@ -14532,7 +14533,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
if (accept1(parser, PM_TOKEN_LESS_LESS)) {
pm_token_t operator = parser->previous;
- pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_NOT, PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS);
+ pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_NOT, PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS, true);
pm_constant_id_t old_param_name = parser->current_param_name;
parser->current_param_name = 0;
@@ -14560,7 +14561,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
return (pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &operator, expression, statements, &parser->previous);
}
- pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_CLASS_NAME);
+ pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_CLASS_NAME, false);
pm_token_t name = parser->previous;
if (name.type != PM_TOKEN_CONSTANT) {
pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
@@ -14576,7 +14577,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
parser->command_start = true;
parser_lex(parser);
- superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CLASS_SUPERCLASS);
+ superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CLASS_SUPERCLASS, true);
} else {
inheritance_operator = not_provided(parser);
superclass = NULL;
@@ -14736,7 +14737,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
parser_lex(parser);
pm_token_t lparen = parser->previous;
- pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_DEF_RECEIVER);
+ pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_DEF_RECEIVER, true);
expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
pm_token_t rparen = parser->previous;
@@ -14825,11 +14826,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
pm_do_loop_stack_push(parser, false);
statements = (pm_node_t *) pm_statements_node_create(parser);
- pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, PM_ERR_DEF_ENDLESS);
+ pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, PM_ERR_DEF_ENDLESS, binding_power < PM_BINDING_POWER_COMPOSITION);
if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
pm_token_t rescue_keyword = parser->previous;
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_RESCUE_MODIFIER_VALUE);
+ pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_RESCUE_MODIFIER_VALUE, false);
pm_rescue_modifier_node_t *rescue_node = pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
statement = (pm_node_t *)rescue_node;
}
@@ -14898,7 +14899,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
lparen = parser->previous;
- expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_DEFINED_EXPRESSION);
+ expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_DEFINED_EXPRESSION, true);
if (parser->recovering) {
rparen = not_provided(parser);
@@ -14909,7 +14910,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
} else {
lparen = not_provided(parser);
rparen = not_provided(parser);
- expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_DEFINED_EXPRESSION);
+ expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_DEFINED_EXPRESSION, false);
}
return (pm_node_t *) pm_defined_node_create(
@@ -14955,12 +14956,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
pm_node_t *name = NULL;
if (token_begins_expression_p(parser->current.type)) {
- name = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR);
+ name = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, false);
}
index = (pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
} else if (token_begins_expression_p(parser->current.type)) {
- index = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA);
+ index = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, false);
} else {
pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
index = (pm_node_t *) pm_missing_node_create(parser, for_keyword.start, for_keyword.end);
@@ -14979,7 +14980,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
pm_token_t in_keyword = parser->previous;
- pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_FOR_COLLECTION);
+ pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_FOR_COLLECTION, true);
pm_do_loop_stack_pop(parser);
pm_token_t do_keyword;
@@ -15047,7 +15048,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
arguments.closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
} else {
- receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_NOT_EXPRESSION);
+ receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_NOT_EXPRESSION, true);
pm_conditional_predicate(receiver);
if (!parser->recovering) {
@@ -15057,7 +15058,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
}
}
} else {
- receiver = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_NOT_EXPRESSION);
+ receiver = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_NOT_EXPRESSION, true);
pm_conditional_predicate(receiver);
}
@@ -15070,7 +15071,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
parser_lex(parser);
pm_token_t module_keyword = parser->previous;
- pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_MODULE_NAME);
+ pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_MODULE_NAME, false);
pm_token_t name;
// If we can recover from a syntax error that occurred while parsing
@@ -15146,7 +15147,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
parser_lex(parser);
pm_token_t keyword = parser->previous;
- pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
+ pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, true);
pm_do_loop_stack_pop(parser);
expect3(parser, PM_TOKEN_KEYWORD_DO_LOOP, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
@@ -15167,7 +15168,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
parser_lex(parser);
pm_token_t keyword = parser->previous;
- pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
+ pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CONDITIONAL_WHILE_PREDICATE, true);
pm_do_loop_stack_pop(parser);
expect3(parser, PM_TOKEN_KEYWORD_DO_LOOP, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
@@ -15691,7 +15692,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
pm_node_t *name = NULL;
if (token_begins_expression_p(parser->current.type)) {
- name = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR);
+ name = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, false);
}
pm_node_t *splat = (pm_node_t *) pm_splat_node_create(parser, &operator, name);
@@ -15706,7 +15707,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
parser_lex(parser);
pm_token_t operator = parser->previous;
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_BANG);
+ pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_BANG, binding_power < PM_BINDING_POWER_COMPOSITION);
pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "!");
pm_conditional_predicate(receiver);
@@ -15716,7 +15717,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
parser_lex(parser);
pm_token_t operator = parser->previous;
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_TILDE);
+ pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_TILDE, false);
pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "~");
return (pm_node_t *) node;
@@ -15725,7 +15726,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
parser_lex(parser);
pm_token_t operator = parser->previous;
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_MINUS);
+ pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_MINUS, false);
pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "-@");
return (pm_node_t *) node;
@@ -15734,11 +15735,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
parser_lex(parser);
pm_token_t operator = parser->previous;
- pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_MINUS);
+ pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_MINUS, false);
if (accept1(parser, PM_TOKEN_STAR_STAR)) {
pm_token_t exponent_operator = parser->previous;
- pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.type].right, PM_ERR_EXPECT_ARGUMENT);
+ pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.type].right, PM_ERR_EXPECT_ARGUMENT, false);
node = (pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent);
node = (pm_node_t *) pm_call_node_unary_create(parser, &operator, node, "-@");
} else {
@@ -15845,7 +15846,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
parser_lex(parser);
pm_token_t operator = parser->previous;
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_PLUS);
+ pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_PLUS, false);
pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "+@");
return (pm_node_t *) node;
@@ -15868,14 +15869,14 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
}
static inline pm_node_t *
-parse_assignment_value(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id) {
- pm_node_t *value = parse_value_expression(parser, binding_power, diag_id);
+parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id, bool accepts_command_call) {
+ pm_node_t *value = parse_value_expression(parser, binding_power, diag_id, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_COMPOSITION);
// Contradicting binding powers, the right-hand-side value of rthe assignment allows the `rescue` modifier.
if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
pm_token_t rescue = parser->current;
parser_lex(parser);
- pm_node_t *right = parse_expression(parser, binding_power, PM_ERR_RESCUE_MODIFIER_VALUE);
+ pm_node_t *right = parse_expression(parser, binding_power, PM_ERR_RESCUE_MODIFIER_VALUE, false);
return (pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
}
@@ -15885,8 +15886,8 @@ parse_assignment_value(pm_parser_t *parser, pm_binding_power_t binding_power, pm
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, pm_diagnostic_id_t diag_id) {
- pm_node_t *value = parse_starred_expression(parser, binding_power, diag_id);
+parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id, bool accepts_command_call) {
+ pm_node_t *value = parse_starred_expression(parser, binding_power, diag_id, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_COMPOSITION);
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))) {
@@ -15898,7 +15899,7 @@ parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding
value = (pm_node_t *) array;
while (accept1(parser, PM_TOKEN_COMMA)) {
- pm_node_t *element = parse_starred_expression(parser, binding_power, PM_ERR_ARRAY_ELEMENT);
+ pm_node_t *element = parse_starred_expression(parser, binding_power, PM_ERR_ARRAY_ELEMENT, false);
pm_array_node_elements_append(array, element);
if (PM_NODE_TYPE_P(element, PM_MISSING_NODE)) break;
}
@@ -15908,7 +15909,7 @@ parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding
if (is_single_value && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
pm_token_t rescue = parser->current;
parser_lex(parser);
- pm_node_t *right = parse_expression(parser, binding_power, PM_ERR_RESCUE_MODIFIER_VALUE);
+ pm_node_t *right = parse_expression(parser, binding_power, PM_ERR_RESCUE_MODIFIER_VALUE, false);
return (pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
}
@@ -16047,7 +16048,7 @@ parse_regular_expression_named_captures(pm_parser_t *parser, const pm_string_t *
}
static inline pm_node_t *
-parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power) {
+parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call) {
pm_token_t token = parser->current;
switch (token.type) {
@@ -16066,7 +16067,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
/* fallthrough */
case PM_CASE_WRITABLE: {
parser_lex(parser);
- pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL);
+ pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) ? PM_BINDING_POWER_MULTI_ASSIGNMENT + 1 : binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, accepts_command_call);
return parse_write(parser, node, &token, value);
}
case PM_SPLAT_NODE: {
@@ -16074,7 +16075,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_multi_target_node_targets_append(parser, multi_target, node);
parser_lex(parser);
- pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL);
+ pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_BINDING_POWER_MULTI_ASSIGNMENT + 1, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, accepts_command_call);
return parse_write(parser, (pm_node_t *) multi_target, &token, value);
}
default:
@@ -16096,7 +16097,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_GLOBAL_VARIABLE_READ_NODE: {
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value);
pm_node_destroy(parser, node);
@@ -16105,7 +16106,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_CLASS_VARIABLE_READ_NODE: {
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_class_variable_and_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value);
pm_node_destroy(parser, node);
@@ -16114,13 +16115,13 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_CONSTANT_PATH_NODE: {
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, accepts_command_call);
return (pm_node_t *) pm_constant_path_and_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
}
case PM_CONSTANT_READ_NODE: {
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_constant_and_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
pm_node_destroy(parser, node);
@@ -16129,7 +16130,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_INSTANCE_VARIABLE_READ_NODE: {
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_instance_variable_and_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value);
pm_node_destroy(parser, node);
@@ -16139,7 +16140,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, cast->name, cast->depth);
pm_node_destroy(parser, node);
@@ -16157,7 +16158,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_refute_numbered_parameter(parser, message_loc->start, message_loc->end);
pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
pm_node_destroy(parser, (pm_node_t *) cast);
@@ -16168,7 +16169,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// this is an aref expression, and we can transform it into
// an aset expression.
if (pm_call_node_index_p(cast)) {
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, accepts_command_call);
return (pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value);
}
@@ -16180,7 +16181,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
}
parse_call_operator_write(parser, cast, &token);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, accepts_command_call);
return (pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value);
}
case PM_MULTI_WRITE_NODE: {
@@ -16207,7 +16208,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_GLOBAL_VARIABLE_READ_NODE: {
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value);
pm_node_destroy(parser, node);
@@ -16216,7 +16217,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_CLASS_VARIABLE_READ_NODE: {
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_class_variable_or_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value);
pm_node_destroy(parser, node);
@@ -16225,13 +16226,13 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_CONSTANT_PATH_NODE: {
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, accepts_command_call);
return (pm_node_t *) pm_constant_path_or_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
}
case PM_CONSTANT_READ_NODE: {
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_constant_or_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
pm_node_destroy(parser, node);
@@ -16240,7 +16241,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_INSTANCE_VARIABLE_READ_NODE: {
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_instance_variable_or_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value);
pm_node_destroy(parser, node);
@@ -16250,7 +16251,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, cast->name, cast->depth);
pm_node_destroy(parser, node);
@@ -16268,7 +16269,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_refute_numbered_parameter(parser, message_loc->start, message_loc->end);
pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
pm_node_destroy(parser, (pm_node_t *) cast);
@@ -16279,7 +16280,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// this is an aref expression, and we can transform it into
// an aset expression.
if (pm_call_node_index_p(cast)) {
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, accepts_command_call);
return (pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value);
}
@@ -16291,7 +16292,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
}
parse_call_operator_write(parser, cast, &token);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, accepts_command_call);
return (pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value);
}
case PM_MULTI_WRITE_NODE: {
@@ -16328,7 +16329,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_GLOBAL_VARIABLE_READ_NODE: {
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value);
pm_node_destroy(parser, node);
@@ -16337,7 +16338,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_CLASS_VARIABLE_READ_NODE: {
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_class_variable_operator_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value);
pm_node_destroy(parser, node);
@@ -16346,13 +16347,13 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_CONSTANT_PATH_NODE: {
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, accepts_command_call);
return (pm_node_t *) pm_constant_path_operator_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
}
case PM_CONSTANT_READ_NODE: {
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_constant_operator_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
pm_node_destroy(parser, node);
@@ -16361,7 +16362,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_INSTANCE_VARIABLE_READ_NODE: {
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_instance_variable_operator_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value);
pm_node_destroy(parser, node);
@@ -16371,7 +16372,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->name, cast->depth);
pm_node_destroy(parser, node);
@@ -16389,7 +16390,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_refute_numbered_parameter(parser, message_loc->start, message_loc->end);
pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, accepts_command_call);
pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
pm_node_destroy(parser, (pm_node_t *) cast);
@@ -16400,7 +16401,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// this is an aref expression, and we can transform it into
// an aset expression.
if (pm_call_node_index_p(cast)) {
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, accepts_command_call);
return (pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value);
}
@@ -16412,7 +16413,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
}
parse_call_operator_write(parser, cast, &token);
- pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, accepts_command_call);
return (pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value);
}
case PM_MULTI_WRITE_NODE: {
@@ -16434,14 +16435,14 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_TOKEN_KEYWORD_AND: {
parser_lex(parser);
- pm_node_t *right = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+ pm_node_t *right = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, parser->previous.type == PM_TOKEN_KEYWORD_AND);
return (pm_node_t *) pm_and_node_create(parser, node, &token, right);
}
case PM_TOKEN_KEYWORD_OR:
case PM_TOKEN_PIPE_PIPE: {
parser_lex(parser);
- pm_node_t *right = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+ pm_node_t *right = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, parser->previous.type == PM_TOKEN_KEYWORD_OR);
return (pm_node_t *) pm_or_node_create(parser, node, &token, right);
}
case PM_TOKEN_EQUAL_TILDE: {
@@ -16453,7 +16454,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
//
// In this case, `foo` should be a method call and not a local yet.
parser_lex(parser);
- pm_node_t *argument = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+ pm_node_t *argument = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, false);
// By default, we're going to create a call node and then return it.
pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument);
@@ -16538,7 +16539,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_TOKEN_STAR_STAR: {
parser_lex(parser);
- pm_node_t *argument = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+ pm_node_t *argument = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, false);
return (pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument);
}
case PM_TOKEN_AMPERSAND_DOT:
@@ -16549,7 +16550,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// This if statement handles the foo.() syntax.
if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
- parse_arguments_list(parser, &arguments, true);
+ parse_arguments_list(parser, &arguments, true, false);
return (pm_node_t *) pm_call_node_shorthand_create(parser, node, &operator, &arguments);
}
@@ -16571,7 +16572,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
}
}
- parse_arguments_list(parser, &arguments, true);
+ parse_arguments_list(parser, &arguments, true, accepts_command_call);
pm_call_node_t *call = pm_call_node_call_create(parser, node, &operator, &message, &arguments);
if (
@@ -16591,7 +16592,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_node_t *right = NULL;
if (token_begins_expression_p(parser->current.type)) {
- right = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
+ right = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, false);
}
return (pm_node_t *) pm_range_node_create(parser, node, &token, right);
@@ -16600,14 +16601,14 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_token_t keyword = parser->current;
parser_lex(parser);
- pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_ERR_CONDITIONAL_IF_PREDICATE);
+ pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_ERR_CONDITIONAL_IF_PREDICATE, true);
return (pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate);
}
case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
pm_token_t keyword = parser->current;
parser_lex(parser);
- pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_ERR_CONDITIONAL_UNLESS_PREDICATE);
+ pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, true);
return (pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate);
}
case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
@@ -16615,7 +16616,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_statements_node_t *statements = pm_statements_node_create(parser);
pm_statements_node_body_append(statements, node);
- pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
+ pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, true);
return (pm_node_t *) pm_until_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0);
}
case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
@@ -16623,13 +16624,13 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_statements_node_t *statements = pm_statements_node_create(parser);
pm_statements_node_body_append(statements, node);
- pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
+ pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_ERR_CONDITIONAL_WHILE_PREDICATE, true);
return (pm_node_t *) pm_while_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0);
}
case PM_TOKEN_QUESTION_MARK: {
pm_token_t qmark = parser->current;
parser_lex(parser);
- pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_TERNARY_EXPRESSION_TRUE);
+ pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_TERNARY_EXPRESSION_TRUE, false);
if (parser->recovering) {
// If parsing the true expression of this ternary resulted in a syntax
@@ -16648,7 +16649,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
pm_token_t colon = parser->previous;
- pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_TERNARY_EXPRESSION_FALSE);
+ pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_TERNARY_EXPRESSION_FALSE, false);
return (pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
}
@@ -16674,7 +16675,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_token_t message = parser->previous;
pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true);
+ parse_arguments_list(parser, &arguments, true, accepts_command_call);
path = (pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
} else {
// Otherwise, this is a constant path. That would look like Foo::Bar.
@@ -16699,7 +16700,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// If we have an identifier following a '::' operator, then it is for
// sure a method call.
pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true);
+ parse_arguments_list(parser, &arguments, true, accepts_command_call);
pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
// If this is followed by a comma then it is a multiple assignment.
@@ -16713,7 +16714,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// If we have a parenthesis following a '::' operator, then it is the
// method call shorthand. That would look like Foo::(bar).
pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true);
+ parse_arguments_list(parser, &arguments, true, false);
return (pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments);
}
@@ -16727,7 +16728,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
parser_lex(parser);
accept1(parser, PM_TOKEN_NEWLINE);
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_RESCUE_MODIFIER_VALUE);
+ pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_RESCUE_MODIFIER_VALUE, true);
return (pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value);
}
@@ -16823,9 +16824,9 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
* determine if they need to perform additional cleanup.
*/
static pm_node_t *
-parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id) {
+parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id, bool accepts_command_call) {
pm_token_t recovery = parser->previous;
- pm_node_t *node = parse_expression_prefix(parser, binding_power);
+ pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call);
switch (PM_NODE_TYPE(node)) {
case PM_MISSING_NODE:
@@ -16866,13 +16867,62 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagn
binding_power <= current_binding_powers.left &&
current_binding_powers.binary
) {
- node = parse_expression_infix(parser, node, binding_power, current_binding_powers.right);
+ node = parse_expression_infix(parser, node, binding_power, current_binding_powers.right, accepts_command_call);
if (
current_binding_powers.nonassoc &&
current_binding_powers.right <= pm_binding_powers[parser->current.type].left
) {
break;
}
+ if (accepts_command_call) {
+ // A command-style method call is only accepted on method chains.
+ // Thus, we check whether the parsed node can continue method chains.
+ // The method chain can continue if the parsed node is one of the following five kinds:
+ // (1) index access: foo[1]
+ // (2) attribute access: foo.bar
+ // (3) method call with parenthesis: foo.bar(1)
+ // (4) method call with a block: foo.bar do end
+ // (5) constant path: foo::Bar
+ switch (node->type) {
+ case PM_CALL_NODE: {
+ pm_call_node_t *cast = (pm_call_node_t *)node;
+ if (
+ // (1) foo[1]
+ !(
+ cast->call_operator_loc.start == NULL &&
+ cast->message_loc.start != NULL &&
+ cast->message_loc.start[0] == '[' &&
+ cast->message_loc.end[-1] == ']'
+ ) &&
+ // (2) foo.bar
+ !(
+ cast->call_operator_loc.start != NULL &&
+ cast->arguments == NULL &&
+ cast->opening_loc.start == NULL
+ ) &&
+ // (3) foo.bar(1)
+ !(
+ cast->call_operator_loc.start != NULL &&
+ cast->arguments != NULL &&
+ cast->opening_loc.start != NULL
+ ) &&
+ // (4) foo.bar do end
+ !(
+ cast->block != NULL && PM_NODE_TYPE_P(cast->block, PM_BLOCK_NODE)
+ )
+ ) {
+ accepts_command_call = false;
+ }
+ break;
+ }
+ // (5) foo::Bar
+ case PM_CONSTANT_PATH_NODE:
+ break;
+ default:
+ accepts_command_call = false;
+ break;
+ }
+ }
}
return node;
diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb
index df41da493a..bb32608e7a 100644
--- a/test/prism/errors_test.rb
+++ b/test/prism/errors_test.rb
@@ -1895,6 +1895,42 @@ module Prism
], compare_ripper: false # Ripper does not check 'circular reference'.
end
+ def test_command_calls
+ sources = <<~RUBY.lines
+ [a b]
+ {a: b c}
+ ...a b
+ if ...a b; end
+ a b, c d
+ a(b, c d)
+ a(*b c)
+ a(**b c)
+ a(&b c)
+ +a b
+ a + b c
+ a && b c
+ a =~ b c
+ a = b, c d
+ a = *b c
+ a, b = c = d f
+ a ? b c : d e
+ defined? a b
+ def f a = b c; end
+ def f(a = b c); end
+ ->a=b c{}
+ ->(a=b c){}
+ case; when a b; end
+ case; in a if a b; end
+ case; in a unless a b; end
+ begin; rescue a b; end
+ begin; rescue a b => c; end
+ RUBY
+ sources.each do |source|
+ assert_nil Ripper.sexp_raw(source)
+ assert_false(Prism.parse(source).success?)
+ end
+ end
+
private
def assert_errors(expected, source, errors, compare_ripper: RUBY_ENGINE == "ruby")
diff --git a/test/prism/fixtures/command_method_call.txt b/test/prism/fixtures/command_method_call.txt
new file mode 100644
index 0000000000..b1652e4ee3
--- /dev/null
+++ b/test/prism/fixtures/command_method_call.txt
@@ -0,0 +1,31 @@
+foo 1
+
+foo bar 1
+
+foo 1 if bar 2
+
+foo 1 unless bar 2
+
+foo 1 while bar 2
+
+foo 1 until bar 2
+
+foo 1 rescue bar 2
+
+foo[bar 1]
+
+foo 1 and bar 2
+
+not foo 1
+
+foo = bar = baz 1
+
+def foo = bar 1
+
+1.foo 2
+
+1.foo.bar 2
+
+1.foo[2].bar 3
+
+1.foo(2).bar 3
diff --git a/test/prism/snapshots/command_method_call.txt b/test/prism/snapshots/command_method_call.txt
new file mode 100644
index 0000000000..1e56788e91
--- /dev/null
+++ b/test/prism/snapshots/command_method_call.txt
@@ -0,0 +1,508 @@
+@ ProgramNode (location: (1,0)-(31,14))
+├── locals: [:foo, :bar]
+└── statements:
+ @ StatementsNode (location: (1,0)-(31,14))
+ └── body: (length: 16)
+ ├── @ CallNode (location: (1,0)-(1,5))
+ │ ├── receiver: ∅
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :foo
+ │ ├── message_loc: (1,0)-(1,3) = "foo"
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (1,4)-(1,5))
+ │ │ ├── arguments: (length: 1)
+ │ │ │ └── @ IntegerNode (location: (1,4)-(1,5))
+ │ │ │ └── flags: decimal
+ │ │ └── flags: ∅
+ │ ├── closing_loc: ∅
+ │ ├── block: ∅
+ │ └── flags: ∅
+ ├── @ CallNode (location: (3,0)-(3,9))
+ │ ├── receiver: ∅
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :foo
+ │ ├── message_loc: (3,0)-(3,3) = "foo"
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (3,4)-(3,9))
+ │ │ ├── arguments: (length: 1)
+ │ │ │ └── @ CallNode (location: (3,4)-(3,9))
+ │ │ │ ├── receiver: ∅
+ │ │ │ ├── call_operator_loc: ∅
+ │ │ │ ├── name: :bar
+ │ │ │ ├── message_loc: (3,4)-(3,7) = "bar"
+ │ │ │ ├── opening_loc: ∅
+ │ │ │ ├── arguments:
+ │ │ │ │ @ ArgumentsNode (location: (3,8)-(3,9))
+ │ │ │ │ ├── arguments: (length: 1)
+ │ │ │ │ │ └── @ IntegerNode (location: (3,8)-(3,9))
+ │ │ │ │ │ └── flags: decimal
+ │ │ │ │ └── flags: ∅
+ │ │ │ ├── closing_loc: ∅
+ │ │ │ ├── block: ∅
+ │ │ │ └── flags: ∅
+ │ │ └── flags: ∅
+ │ ├── closing_loc: ∅
+ │ ├── block: ∅
+ │ └── flags: ∅
+ ├── @ IfNode (location: (5,0)-(5,14))
+ │ ├── if_keyword_loc: (5,6)-(5,8) = "if"
+ │ ├── predicate:
+ │ │ @ CallNode (location: (5,9)-(5,14))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── name: :bar
+ │ │ ├── message_loc: (5,9)-(5,12) = "bar"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments:
+ │ │ │ @ ArgumentsNode (location: (5,13)-(5,14))
+ │ │ │ ├── arguments: (length: 1)
+ │ │ │ │ └── @ IntegerNode (location: (5,13)-(5,14))
+ │ │ │ │ └── flags: decimal
+ │ │ │ └── flags: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ └── flags: ∅
+ │ ├── then_keyword_loc: ∅
+ │ ├── statements:
+ │ │ @ StatementsNode (location: (5,0)-(5,5))
+ │ │ └── body: (length: 1)
+ │ │ └── @ CallNode (location: (5,0)-(5,5))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── name: :foo
+ │ │ ├── message_loc: (5,0)-(5,3) = "foo"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments:
+ │ │ │ @ ArgumentsNode (location: (5,4)-(5,5))
+ │ │ │ ├── arguments: (length: 1)
+ │ │ │ │ └── @ IntegerNode (location: (5,4)-(5,5))
+ │ │ │ │ └── flags: decimal
+ │ │ │ └── flags: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ └── flags: ∅
+ │ ├── consequent: ∅
+ │ └── end_keyword_loc: ∅
+ ├── @ UnlessNode (location: (7,0)-(7,18))
+ │ ├── keyword_loc: (7,6)-(7,12) = "unless"
+ │ ├── predicate:
+ │ │ @ CallNode (location: (7,13)-(7,18))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── name: :bar
+ │ │ ├── message_loc: (7,13)-(7,16) = "bar"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments:
+ │ │ │ @ ArgumentsNode (location: (7,17)-(7,18))
+ │ │ │ ├── arguments: (length: 1)
+ │ │ │ │ └── @ IntegerNode (location: (7,17)-(7,18))
+ │ │ │ │ └── flags: decimal
+ │ │ │ └── flags: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ └── flags: ∅
+ │ ├── then_keyword_loc: ∅
+ │ ├── statements:
+ │ │ @ StatementsNode (location: (7,0)-(7,5))
+ │ │ └── body: (length: 1)
+ │ │ └── @ CallNode (location: (7,0)-(7,5))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── name: :foo
+ │ │ ├── message_loc: (7,0)-(7,3) = "foo"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments:
+ │ │ │ @ ArgumentsNode (location: (7,4)-(7,5))
+ │ │ │ ├── arguments: (length: 1)
+ │ │ │ │ └── @ IntegerNode (location: (7,4)-(7,5))
+ │ │ │ │ └── flags: decimal
+ │ │ │ └── flags: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ └── flags: ∅
+ │ ├── consequent: ∅
+ │ └── end_keyword_loc: ∅
+ ├── @ WhileNode (location: (9,0)-(9,17))
+ │ ├── keyword_loc: (9,6)-(9,11) = "while"
+ │ ├── closing_loc: ∅
+ │ ├── predicate:
+ │ │ @ CallNode (location: (9,12)-(9,17))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── name: :bar
+ │ │ ├── message_loc: (9,12)-(9,15) = "bar"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments:
+ │ │ │ @ ArgumentsNode (location: (9,16)-(9,17))
+ │ │ │ ├── arguments: (length: 1)
+ │ │ │ │ └── @ IntegerNode (location: (9,16)-(9,17))
+ │ │ │ │ └── flags: decimal
+ │ │ │ └── flags: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ └── flags: ∅
+ │ ├── statements:
+ │ │ @ StatementsNode (location: (9,0)-(9,5))
+ │ │ └── body: (length: 1)
+ │ │ └── @ CallNode (location: (9,0)-(9,5))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── name: :foo
+ │ │ ├── message_loc: (9,0)-(9,3) = "foo"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments:
+ │ │ │ @ ArgumentsNode (location: (9,4)-(9,5))
+ │ │ │ ├── arguments: (length: 1)
+ │ │ │ │ └── @ IntegerNode (location: (9,4)-(9,5))
+ │ │ │ │ └── flags: decimal
+ │ │ │ └── flags: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ └── flags: ∅
+ │ └── flags: ∅
+ ├── @ UntilNode (location: (11,0)-(11,17))
+ │ ├── keyword_loc: (11,6)-(11,11) = "until"
+ │ ├── closing_loc: ∅
+ │ ├── predicate:
+ │ │ @ CallNode (location: (11,12)-(11,17))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── name: :bar
+ │ │ ├── message_loc: (11,12)-(11,15) = "bar"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments:
+ │ │ │ @ ArgumentsNode (location: (11,16)-(11,17))
+ │ │ │ ├── arguments: (length: 1)
+ │ │ │ │ └── @ IntegerNode (location: (11,16)-(11,17))
+ │ │ │ │ └── flags: decimal
+ │ │ │ └── flags: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ └── flags: ∅
+ │ ├── statements:
+ │ │ @ StatementsNode (location: (11,0)-(11,5))
+ │ │ └── body: (length: 1)
+ │ │ └── @ CallNode (location: (11,0)-(11,5))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── name: :foo
+ │ │ ├── message_loc: (11,0)-(11,3) = "foo"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments:
+ │ │ │ @ ArgumentsNode (location: (11,4)-(11,5))
+ │ │ │ ├── arguments: (length: 1)
+ │ │ │ │ └── @ IntegerNode (location: (11,4)-(11,5))
+ │ │ │ │ └── flags: decimal
+ │ │ │ └── flags: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ └── flags: ∅
+ │ └── flags: ∅
+ ├── @ RescueModifierNode (location: (13,0)-(13,18))
+ │ ├── expression:
+ │ │ @ CallNode (location: (13,0)-(13,5))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── name: :foo
+ │ │ ├── message_loc: (13,0)-(13,3) = "foo"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments:
+ │ │ │ @ ArgumentsNode (location: (13,4)-(13,5))
+ │ │ │ ├── arguments: (length: 1)
+ │ │ │ │ └── @ IntegerNode (location: (13,4)-(13,5))
+ │ │ │ │ └── flags: decimal
+ │ │ │ └── flags: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ └── flags: ∅
+ │ ├── keyword_loc: (13,6)-(13,12) = "rescue"
+ │ └── rescue_expression:
+ │ @ CallNode (location: (13,13)-(13,18))
+ │ ├── receiver: ∅
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :bar
+ │ ├── message_loc: (13,13)-(13,16) = "bar"
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (13,17)-(13,18))
+ │ │ ├── arguments: (length: 1)
+ │ │ │ └── @ IntegerNode (location: (13,17)-(13,18))
+ │ │ │ └── flags: decimal
+ │ │ └── flags: ∅
+ │ ├── closing_loc: ∅
+ │ ├── block: ∅
+ │ └── flags: ∅
+ ├── @ CallNode (location: (15,0)-(15,10))
+ │ ├── receiver:
+ │ │ @ CallNode (location: (15,0)-(15,3))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── name: :foo
+ │ │ ├── message_loc: (15,0)-(15,3) = "foo"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ └── flags: variable_call
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :[]
+ │ ├── message_loc: (15,3)-(15,10) = "[bar 1]"
+ │ ├── opening_loc: (15,3)-(15,4) = "["
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (15,4)-(15,9))
+ │ │ ├── arguments: (length: 1)
+ │ │ │ └── @ CallNode (location: (15,4)-(15,9))
+ │ │ │ ├── receiver: ∅
+ │ │ │ ├── call_operator_loc: ∅
+ │ │ │ ├── name: :bar
+ │ │ │ ├── message_loc: (15,4)-(15,7) = "bar"
+ │ │ │ ├── opening_loc: ∅
+ │ │ │ ├── arguments:
+ │ │ │ │ @ ArgumentsNode (location: (15,8)-(15,9))
+ │ │ │ │ ├── arguments: (length: 1)
+ │ │ │ │ │ └── @ IntegerNode (location: (15,8)-(15,9))
+ │ │ │ │ │ └── flags: decimal
+ │ │ │ │ └── flags: ∅
+ │ │ │ ├── closing_loc: ∅
+ │ │ │ ├── block: ∅
+ │ │ │ └── flags: ∅
+ │ │ └── flags: ∅
+ │ ├── closing_loc: (15,9)-(15,10) = "]"
+ │ ├── block: ∅
+ │ └── flags: ∅
+ ├── @ AndNode (location: (17,0)-(17,15))
+ │ ├── left:
+ │ │ @ CallNode (location: (17,0)-(17,5))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── name: :foo
+ │ │ ├── message_loc: (17,0)-(17,3) = "foo"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments:
+ │ │ │ @ ArgumentsNode (location: (17,4)-(17,5))
+ │ │ │ ├── arguments: (length: 1)
+ │ │ │ │ └── @ IntegerNode (location: (17,4)-(17,5))
+ │ │ │ │ └── flags: decimal
+ │ │ │ └── flags: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ └── flags: ∅
+ │ ├── right:
+ │ │ @ CallNode (location: (17,10)-(17,15))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── name: :bar
+ │ │ ├── message_loc: (17,10)-(17,13) = "bar"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments:
+ │ │ │ @ ArgumentsNode (location: (17,14)-(17,15))
+ │ │ │ ├── arguments: (length: 1)
+ │ │ │ │ └── @ IntegerNode (location: (17,14)-(17,15))
+ │ │ │ │ └── flags: decimal
+ │ │ │ └── flags: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ └── flags: ∅
+ │ └── operator_loc: (17,6)-(17,9) = "and"
+ ├── @ CallNode (location: (19,0)-(19,9))
+ │ ├── receiver:
+ │ │ @ CallNode (location: (19,4)-(19,9))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── name: :foo
+ │ │ ├── message_loc: (19,4)-(19,7) = "foo"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments:
+ │ │ │ @ ArgumentsNode (location: (19,8)-(19,9))
+ │ │ │ ├── arguments: (length: 1)
+ │ │ │ │ └── @ IntegerNode (location: (19,8)-(19,9))
+ │ │ │ │ └── flags: decimal
+ │ │ │ └── flags: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ └── flags: ∅
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :!
+ │ ├── message_loc: (19,0)-(19,3) = "not"
+ │ ├── opening_loc: ∅
+ │ ├── arguments: ∅
+ │ ├── closing_loc: ∅
+ │ ├── block: ∅
+ │ └── flags: ∅
+ ├── @ LocalVariableWriteNode (location: (21,0)-(21,17))
+ │ ├── name: :foo
+ │ ├── depth: 0
+ │ ├── name_loc: (21,0)-(21,3) = "foo"
+ │ ├── value:
+ │ │ @ LocalVariableWriteNode (location: (21,6)-(21,17))
+ │ │ ├── name: :bar
+ │ │ ├── depth: 0
+ │ │ ├── name_loc: (21,6)-(21,9) = "bar"
+ │ │ ├── value:
+ │ │ │ @ CallNode (location: (21,12)-(21,17))
+ │ │ │ ├── receiver: ∅
+ │ │ │ ├── call_operator_loc: ∅
+ │ │ │ ├── name: :baz
+ │ │ │ ├── message_loc: (21,12)-(21,15) = "baz"
+ │ │ │ ├── opening_loc: ∅
+ │ │ │ ├── arguments:
+ │ │ │ │ @ ArgumentsNode (location: (21,16)-(21,17))
+ │ │ │ │ ├── arguments: (length: 1)
+ │ │ │ │ │ └── @ IntegerNode (location: (21,16)-(21,17))
+ │ │ │ │ │ └── flags: decimal
+ │ │ │ │ └── flags: ∅
+ │ │ │ ├── closing_loc: ∅
+ │ │ │ ├── block: ∅
+ │ │ │ └── flags: ∅
+ │ │ └── operator_loc: (21,10)-(21,11) = "="
+ │ └── operator_loc: (21,4)-(21,5) = "="
+ ├── @ DefNode (location: (23,0)-(23,15))
+ │ ├── name: :foo
+ │ ├── name_loc: (23,4)-(23,7) = "foo"
+ │ ├── receiver: ∅
+ │ ├── parameters: ∅
+ │ ├── body:
+ │ │ @ StatementsNode (location: (23,10)-(23,15))
+ │ │ └── body: (length: 1)
+ │ │ └── @ CallNode (location: (23,10)-(23,15))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── name: :bar
+ │ │ ├── message_loc: (23,10)-(23,13) = "bar"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments:
+ │ │ │ @ ArgumentsNode (location: (23,14)-(23,15))
+ │ │ │ ├── arguments: (length: 1)
+ │ │ │ │ └── @ IntegerNode (location: (23,14)-(23,15))
+ │ │ │ │ └── flags: decimal
+ │ │ │ └── flags: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ └── flags: ∅
+ │ ├── locals: []
+ │ ├── def_keyword_loc: (23,0)-(23,3) = "def"
+ │ ├── operator_loc: ∅
+ │ ├── lparen_loc: ∅
+ │ ├── rparen_loc: ∅
+ │ ├── equal_loc: (23,8)-(23,9) = "="
+ │ └── end_keyword_loc: ∅
+ ├── @ CallNode (location: (25,0)-(25,7))
+ │ ├── receiver:
+ │ │ @ IntegerNode (location: (25,0)-(25,1))
+ │ │ └── flags: decimal
+ │ ├── call_operator_loc: (25,1)-(25,2) = "."
+ │ ├── name: :foo
+ │ ├── message_loc: (25,2)-(25,5) = "foo"
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (25,6)-(25,7))
+ │ │ ├── arguments: (length: 1)
+ │ │ │ └── @ IntegerNode (location: (25,6)-(25,7))
+ │ │ │ └── flags: decimal
+ │ │ └── flags: ∅
+ │ ├── closing_loc: ∅
+ │ ├── block: ∅
+ │ └── flags: ∅
+ ├── @ CallNode (location: (27,0)-(27,11))
+ │ ├── receiver:
+ │ │ @ CallNode (location: (27,0)-(27,5))
+ │ │ ├── receiver:
+ │ │ │ @ IntegerNode (location: (27,0)-(27,1))
+ │ │ │ └── flags: decimal
+ │ │ ├── call_operator_loc: (27,1)-(27,2) = "."
+ │ │ ├── name: :foo
+ │ │ ├── message_loc: (27,2)-(27,5) = "foo"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ └── flags: ∅
+ │ ├── call_operator_loc: (27,5)-(27,6) = "."
+ │ ├── name: :bar
+ │ ├── message_loc: (27,6)-(27,9) = "bar"
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (27,10)-(27,11))
+ │ │ ├── arguments: (length: 1)
+ │ │ │ └── @ IntegerNode (location: (27,10)-(27,11))
+ │ │ │ └── flags: decimal
+ │ │ └── flags: ∅
+ │ ├── closing_loc: ∅
+ │ ├── block: ∅
+ │ └── flags: ∅
+ ├── @ CallNode (location: (29,0)-(29,14))
+ │ ├── receiver:
+ │ │ @ CallNode (location: (29,0)-(29,8))
+ │ │ ├── receiver:
+ │ │ │ @ CallNode (location: (29,0)-(29,5))
+ │ │ │ ├── receiver:
+ │ │ │ │ @ IntegerNode (location: (29,0)-(29,1))
+ │ │ │ │ └── flags: decimal
+ │ │ │ ├── call_operator_loc: (29,1)-(29,2) = "."
+ │ │ │ ├── name: :foo
+ │ │ │ ├── message_loc: (29,2)-(29,5) = "foo"
+ │ │ │ ├── opening_loc: ∅
+ │ │ │ ├── arguments: ∅
+ │ │ │ ├── closing_loc: ∅
+ │ │ │ ├── block: ∅
+ │ │ │ └── flags: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── name: :[]
+ │ │ ├── message_loc: (29,5)-(29,8) = "[2]"
+ │ │ ├── opening_loc: (29,5)-(29,6) = "["
+ │ │ ├── arguments:
+ │ │ │ @ ArgumentsNode (location: (29,6)-(29,7))
+ │ │ │ ├── arguments: (length: 1)
+ │ │ │ │ └── @ IntegerNode (location: (29,6)-(29,7))
+ │ │ │ │ └── flags: decimal
+ │ │ │ └── flags: ∅
+ │ │ ├── closing_loc: (29,7)-(29,8) = "]"
+ │ │ ├── block: ∅
+ │ │ └── flags: ∅
+ │ ├── call_operator_loc: (29,8)-(29,9) = "."
+ │ ├── name: :bar
+ │ ├── message_loc: (29,9)-(29,12) = "bar"
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (29,13)-(29,14))
+ │ │ ├── arguments: (length: 1)
+ │ │ │ └── @ IntegerNode (location: (29,13)-(29,14))
+ │ │ │ └── flags: decimal
+ │ │ └── flags: ∅
+ │ ├── closing_loc: ∅
+ │ ├── block: ∅
+ │ └── flags: ∅
+ └── @ CallNode (location: (31,0)-(31,14))
+ ├── receiver:
+ │ @ CallNode (location: (31,0)-(31,8))
+ │ ├── receiver:
+ │ │ @ IntegerNode (location: (31,0)-(31,1))
+ │ │ └── flags: decimal
+ │ ├── call_operator_loc: (31,1)-(31,2) = "."
+ │ ├── name: :foo
+ │ ├── message_loc: (31,2)-(31,5) = "foo"
+ │ ├── opening_loc: (31,5)-(31,6) = "("
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (31,6)-(31,7))
+ │ │ ├── arguments: (length: 1)
+ │ │ │ └── @ IntegerNode (location: (31,6)-(31,7))
+ │ │ │ └── flags: decimal
+ │ │ └── flags: ∅
+ │ ├── closing_loc: (31,7)-(31,8) = ")"
+ │ ├── block: ∅
+ │ └── flags: ∅
+ ├── call_operator_loc: (31,8)-(31,9) = "."
+ ├── name: :bar
+ ├── message_loc: (31,9)-(31,12) = "bar"
+ ├── opening_loc: ∅
+ ├── arguments:
+ │ @ ArgumentsNode (location: (31,13)-(31,14))
+ │ ├── arguments: (length: 1)
+ │ │ └── @ IntegerNode (location: (31,13)-(31,14))
+ │ │ └── flags: decimal
+ │ └── flags: ∅
+ ├── closing_loc: ∅
+ ├── block: ∅
+ └── flags: ∅