diff --git a/src/prism.c b/src/prism.c index c06899b1d0..135b9c774a 100644 --- a/src/prism.c +++ b/src/prism.c @@ -11452,10 +11452,7 @@ parser_lex(pm_parser_t *parser) { if (match(parser, '.')) { if (match(parser, '.')) { // If we're _not_ inside a range within default parameters - if ( - !context_p(parser, PM_CONTEXT_DEFAULT_PARAMS) && - context_p(parser, PM_CONTEXT_DEF_PARAMS) - ) { + if (!context_p(parser, PM_CONTEXT_DEFAULT_PARAMS) && context_p(parser, PM_CONTEXT_DEF_PARAMS)) { if (lex_state_p(parser, PM_LEX_STATE_END)) { lex_state_set(parser, PM_LEX_STATE_BEG); } else { @@ -14572,9 +14569,10 @@ parse_parameters( bool repeated = pm_parser_parameter_name_check(parser, &name); pm_parser_local_add_token(parser, &name, 1); - if (accept1(parser, PM_TOKEN_EQUAL)) { - pm_token_t operator = parser->previous; + if (match1(parser, PM_TOKEN_EQUAL)) { + pm_token_t operator = parser->current; context_push(parser, PM_CONTEXT_DEFAULT_PARAMS); + parser_lex(parser); pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &name); uint32_t reads = parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0; @@ -14625,6 +14623,8 @@ parse_parameters( case PM_TOKEN_LABEL: { if (!uses_parentheses) parser->in_keyword_arg = true; update_parameter_state(parser, &parser->current, &order); + + context_push(parser, PM_CONTEXT_DEFAULT_PARAMS); parser_lex(parser); pm_token_t name = parser->previous; @@ -14644,15 +14644,20 @@ parse_parameters( case PM_TOKEN_COMMA: case PM_TOKEN_PARENTHESIS_RIGHT: case PM_TOKEN_PIPE: { + context_pop(parser); + pm_node_t *param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name); if (repeated) { pm_node_flag_set_repeated_parameter(param); } + pm_parameters_node_keywords_append(params, param); break; } case PM_TOKEN_SEMICOLON: case PM_TOKEN_NEWLINE: { + context_pop(parser); + if (uses_parentheses) { looping = false; break; @@ -14662,6 +14667,7 @@ parse_parameters( if (repeated) { pm_node_flag_set_repeated_parameter(param); } + pm_parameters_node_keywords_append(params, param); break; } @@ -14669,8 +14675,6 @@ parse_parameters( pm_node_t *param; if (token_begins_expression_p(parser->current.type)) { - context_push(parser, PM_CONTEXT_DEFAULT_PARAMS); - pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &local); uint32_t reads = parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0; @@ -14682,7 +14686,6 @@ parse_parameters( PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR); } - context_pop(parser); param = (pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value); } else { @@ -14692,6 +14695,8 @@ parse_parameters( if (repeated) { pm_node_flag_set_repeated_parameter(param); } + + context_pop(parser); pm_parameters_node_keywords_append(params, param); // If parsing the value of the parameter resulted in error recovery, @@ -19247,6 +19252,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b lex_state_set(parser, PM_LEX_STATE_BEG); parser->command_start = true; + context_pop(parser); if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) { PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_DEF_PARAMS_TERM_PAREN, pm_token_type_human(parser->current.type)); parser->previous.start = parser->previous.end; @@ -19266,17 +19272,20 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b lparen = not_provided(parser); rparen = not_provided(parser); params = parse_parameters(parser, PM_BINDING_POWER_DEFINED, false, false, true, true, (uint16_t) (depth + 1)); + + context_pop(parser); break; } default: { lparen = not_provided(parser); rparen = not_provided(parser); params = NULL; + + context_pop(parser); break; } } - context_pop(parser); pm_node_t *statements = NULL; pm_token_t equal; pm_token_t end_keyword; diff --git a/test/prism/fixtures/range_beginless.txt b/test/prism/fixtures/range_beginless.txt new file mode 100644 index 0000000000..a55b9b57e7 --- /dev/null +++ b/test/prism/fixtures/range_beginless.txt @@ -0,0 +1,5 @@ +def f(x = ...?a); end + +def f(x: ...?a); end + +def f() ...:a; end diff --git a/test/prism/snapshots/range_beginless.txt b/test/prism/snapshots/range_beginless.txt new file mode 100644 index 0000000000..800f087dc1 --- /dev/null +++ b/test/prism/snapshots/range_beginless.txt @@ -0,0 +1,114 @@ +@ ProgramNode (location: (1,0)-(5,18)) +├── flags: ∅ +├── locals: [] +└── statements: + @ StatementsNode (location: (1,0)-(5,18)) + ├── flags: ∅ + └── body: (length: 3) + ├── @ DefNode (location: (1,0)-(1,21)) + │ ├── flags: newline + │ ├── name: :f + │ ├── name_loc: (1,4)-(1,5) = "f" + │ ├── receiver: ∅ + │ ├── parameters: + │ │ @ ParametersNode (location: (1,6)-(1,15)) + │ │ ├── flags: ∅ + │ │ ├── requireds: (length: 0) + │ │ ├── optionals: (length: 1) + │ │ │ └── @ OptionalParameterNode (location: (1,6)-(1,15)) + │ │ │ ├── flags: ∅ + │ │ │ ├── name: :x + │ │ │ ├── name_loc: (1,6)-(1,7) = "x" + │ │ │ ├── operator_loc: (1,8)-(1,9) = "=" + │ │ │ └── value: + │ │ │ @ RangeNode (location: (1,10)-(1,15)) + │ │ │ ├── flags: exclude_end + │ │ │ ├── left: ∅ + │ │ │ ├── right: + │ │ │ │ @ StringNode (location: (1,13)-(1,15)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ ├── opening_loc: (1,13)-(1,14) = "?" + │ │ │ │ ├── content_loc: (1,14)-(1,15) = "a" + │ │ │ │ ├── closing_loc: ∅ + │ │ │ │ └── unescaped: "a" + │ │ │ └── operator_loc: (1,10)-(1,13) = "..." + │ │ ├── rest: ∅ + │ │ ├── posts: (length: 0) + │ │ ├── keywords: (length: 0) + │ │ ├── keyword_rest: ∅ + │ │ └── block: ∅ + │ ├── body: ∅ + │ ├── locals: [:x] + │ ├── def_keyword_loc: (1,0)-(1,3) = "def" + │ ├── operator_loc: ∅ + │ ├── lparen_loc: (1,5)-(1,6) = "(" + │ ├── rparen_loc: (1,15)-(1,16) = ")" + │ ├── equal_loc: ∅ + │ └── end_keyword_loc: (1,18)-(1,21) = "end" + ├── @ DefNode (location: (3,0)-(3,20)) + │ ├── flags: newline + │ ├── name: :f + │ ├── name_loc: (3,4)-(3,5) = "f" + │ ├── receiver: ∅ + │ ├── parameters: + │ │ @ ParametersNode (location: (3,6)-(3,14)) + │ │ ├── flags: ∅ + │ │ ├── requireds: (length: 0) + │ │ ├── optionals: (length: 0) + │ │ ├── rest: ∅ + │ │ ├── posts: (length: 0) + │ │ ├── keywords: (length: 1) + │ │ │ └── @ OptionalKeywordParameterNode (location: (3,6)-(3,14)) + │ │ │ ├── flags: ∅ + │ │ │ ├── name: :x + │ │ │ ├── name_loc: (3,6)-(3,8) = "x:" + │ │ │ └── value: + │ │ │ @ RangeNode (location: (3,9)-(3,14)) + │ │ │ ├── flags: exclude_end + │ │ │ ├── left: ∅ + │ │ │ ├── right: + │ │ │ │ @ StringNode (location: (3,12)-(3,14)) + │ │ │ │ ├── flags: ∅ + │ │ │ │ ├── opening_loc: (3,12)-(3,13) = "?" + │ │ │ │ ├── content_loc: (3,13)-(3,14) = "a" + │ │ │ │ ├── closing_loc: ∅ + │ │ │ │ └── unescaped: "a" + │ │ │ └── operator_loc: (3,9)-(3,12) = "..." + │ │ ├── keyword_rest: ∅ + │ │ └── block: ∅ + │ ├── body: ∅ + │ ├── locals: [:x] + │ ├── def_keyword_loc: (3,0)-(3,3) = "def" + │ ├── operator_loc: ∅ + │ ├── lparen_loc: (3,5)-(3,6) = "(" + │ ├── rparen_loc: (3,14)-(3,15) = ")" + │ ├── equal_loc: ∅ + │ └── end_keyword_loc: (3,17)-(3,20) = "end" + └── @ DefNode (location: (5,0)-(5,18)) + ├── flags: newline + ├── name: :f + ├── name_loc: (5,4)-(5,5) = "f" + ├── receiver: ∅ + ├── parameters: ∅ + ├── body: + │ @ StatementsNode (location: (5,8)-(5,13)) + │ ├── flags: ∅ + │ └── body: (length: 1) + │ └── @ RangeNode (location: (5,8)-(5,13)) + │ ├── flags: newline, exclude_end + │ ├── left: ∅ + │ ├── right: + │ │ @ SymbolNode (location: (5,11)-(5,13)) + │ │ ├── flags: static_literal, forced_us_ascii_encoding + │ │ ├── opening_loc: (5,11)-(5,12) = ":" + │ │ ├── value_loc: (5,12)-(5,13) = "a" + │ │ ├── closing_loc: ∅ + │ │ └── unescaped: "a" + │ └── operator_loc: (5,8)-(5,11) = "..." + ├── locals: [] + ├── def_keyword_loc: (5,0)-(5,3) = "def" + ├── operator_loc: ∅ + ├── lparen_loc: (5,5)-(5,6) = "(" + ├── rparen_loc: (5,6)-(5,7) = ")" + ├── equal_loc: ∅ + └── end_keyword_loc: (5,15)-(5,18) = "end"