diff --git a/prism/prism.c b/prism/prism.c index 15f99445fbec9d..63595700cd13d8 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 df41da493a4894..bb32608e7ab062 100644 --- a/test/prism/errors_test.rb +++ b/test/prism/errors_test.rb @@ -1895,6 +1895,42 @@ def foo(bar: bar) = 42 ], 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 00000000000000..b1652e4ee38e6d --- /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 00000000000000..1e56788e91aae1 --- /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: ∅