@@ -12422,6 +12422,22 @@ expect1_heredoc_term(pm_parser_t *parser, const uint8_t *ident_start, size_t ide
1242212422 }
1242312423}
1242412424
12425+ /**
12426+ * A special expect1 that attaches the error to the opening token location
12427+ * rather than the current position. This is useful for errors about missing
12428+ * closing tokens, where we want to point to the line with the opening token
12429+ * (e.g., `def`, `class`, `if`, `{`) rather than the end of the file.
12430+ */
12431+ static void
12432+ expect1_opening(pm_parser_t *parser, pm_token_type_t type, pm_diagnostic_id_t diag_id, const pm_token_t *opening) {
12433+ if (accept1(parser, type)) return;
12434+
12435+ pm_parser_err(parser, opening->start, opening->end, diag_id);
12436+
12437+ parser->previous.start = opening->end;
12438+ parser->previous.type = PM_TOKEN_MISSING;
12439+ }
12440+
1242512441static pm_node_t *
1242612442parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, bool accepts_label, pm_diagnostic_id_t diag_id, uint16_t depth);
1242712443
@@ -14764,7 +14780,7 @@ parse_block(pm_parser_t *parser, uint16_t depth) {
1476414780 statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_BRACES, (uint16_t) (depth + 1)));
1476514781 }
1476614782
14767- expect1 (parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE);
14783+ expect1_opening (parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE, &opening );
1476814784 } else {
1476914785 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
1477014786 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
@@ -14779,7 +14795,7 @@ parse_block(pm_parser_t *parser, uint16_t depth) {
1477914795 }
1478014796 }
1478114797
14782- expect1 (parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END);
14798+ expect1_opening (parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END, &opening );
1478314799 }
1478414800
1478514801 pm_constant_id_list_t locals;
@@ -15204,7 +15220,7 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
1520415220
1520515221 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
1520615222 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword, false, false);
15207- expect1 (parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE);
15223+ expect1_opening (parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword );
1520815224
1520915225 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->previous);
1521015226
@@ -15221,7 +15237,7 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
1522115237 }
1522215238 } else {
1522315239 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else, false);
15224- expect1 (parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM);
15240+ expect1_opening (parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword );
1522515241 }
1522615242
1522715243 // Set the appropriate end location for all of the nodes in the subtree.
@@ -16202,7 +16218,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
1620216218 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
1620316219 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
1620416220 accept1(parser, PM_TOKEN_NEWLINE);
16205- expect1 (parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
16221+ expect1_opening (parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening );
1620616222 }
1620716223
1620816224 closing = parser->previous;
@@ -16214,7 +16230,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
1621416230 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
1621516231 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
1621616232 accept1(parser, PM_TOKEN_NEWLINE);
16217- expect1 (parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
16233+ expect1_opening (parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening );
1621816234 }
1621916235
1622016236 closing = parser->previous;
@@ -16594,7 +16610,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
1659416610 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
1659516611
1659616612 accept1(parser, PM_TOKEN_NEWLINE);
16597- expect1 (parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
16613+ expect1_opening (parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening );
1659816614 pm_token_t closing = parser->previous;
1659916615
1660016616 switch (PM_NODE_TYPE(inner)) {
@@ -16672,7 +16688,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
1667216688 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
1667316689
1667416690 accept1(parser, PM_TOKEN_NEWLINE);
16675- expect1 (parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE);
16691+ expect1_opening (parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening );
1667616692 pm_token_t closing = parser->previous;
1667716693
1667816694 node->base.location.start = opening.start;
@@ -16798,7 +16814,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
1679816814 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
1679916815
1680016816 accept1(parser, PM_TOKEN_NEWLINE);
16801- expect1 (parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
16817+ expect1_opening (parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen );
1680216818 return UP(pm_pinned_expression_node_create(parser, expression, &operator, &lparen, &parser->previous));
1680316819 }
1680416820 default: {
@@ -16896,7 +16912,7 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p
1689616912
1689716913 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
1689816914 accept1(parser, PM_TOKEN_NEWLINE);
16899- expect1 (parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
16915+ expect1_opening (parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening );
1690016916 pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->previous, 0));
1690116917
1690216918 if (!alternation) {
@@ -17748,7 +17764,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1774817764 pm_accepts_block_stack_push(parser, true);
1774917765 parser_lex(parser);
1775017766
17751- pm_hash_node_t *node = pm_hash_node_create(parser, &parser->previous);
17767+ pm_token_t opening = parser->previous;
17768+ pm_hash_node_t *node = pm_hash_node_create(parser, &opening);
1775217769
1775317770 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
1775417771 if (current_hash_keys != NULL) {
@@ -17763,7 +17780,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1776317780 }
1776417781
1776517782 pm_accepts_block_stack_pop(parser);
17766- expect1 (parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM);
17783+ expect1_opening (parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening );
1776717784 pm_hash_node_closing_loc_set(node, &parser->previous);
1776817785
1776917786 return UP(node);
@@ -18380,7 +18397,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1838018397 }
1838118398
1838218399 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, false);
18383- expect1 (parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM);
18400+ expect1_opening (parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword );
1838418401
1838518402 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
1838618403 pm_case_node_end_keyword_loc_set((pm_case_node_t *) node, &parser->previous);
@@ -18413,7 +18430,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1841318430
1841418431 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
1841518432 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
18416- expect1 (parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM);
18433+ expect1_opening (parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword );
1841718434
1841818435 begin_node->base.location.end = parser->previous.end;
1841918436 pm_begin_node_end_keyword_set(begin_node, &parser->previous);
@@ -18438,7 +18455,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1843818455 pm_token_t opening = parser->previous;
1843918456 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_PREEXE, (uint16_t) (depth + 1));
1844018457
18441- expect1 (parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM);
18458+ expect1_opening (parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening );
1844218459 pm_context_t context = parser->current_context->context;
1844318460 if ((context != PM_CONTEXT_MAIN) && (context != PM_CONTEXT_PREEXE)) {
1844418461 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
@@ -18568,7 +18585,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1856818585 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword, false, false);
1856918586 }
1857018587
18571- expect1 (parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
18588+ expect1_opening (parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword );
1857218589
1857318590 pm_constant_id_list_t locals;
1857418591 pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
@@ -18626,7 +18643,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1862618643 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword, false, false);
1862718644 }
1862818645
18629- expect1 (parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
18646+ expect1_opening (parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword );
1863018647
1863118648 if (context_def_p(parser)) {
1863218649 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
@@ -18936,7 +18953,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1893618953 pm_accepts_block_stack_pop(parser);
1893718954 pm_do_loop_stack_pop(parser);
1893818955
18939- expect1 (parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM);
18956+ expect1_opening (parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword );
1894018957 end_keyword = parser->previous;
1894118958 }
1894218959
@@ -19030,7 +19047,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1903019047 pm_token_t opening = parser->previous;
1903119048 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_POSTEXE, (uint16_t) (depth + 1));
1903219049
19033- expect1 (parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM);
19050+ expect1_opening (parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening );
1903419051 return UP(pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->previous));
1903519052 }
1903619053 case PM_TOKEN_KEYWORD_FALSE:
@@ -19094,7 +19111,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1909419111 }
1909519112
1909619113 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword, false, false);
19097- expect1 (parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM);
19114+ expect1_opening (parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword );
1909819115
1909919116 return UP(pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->previous));
1910019117 }
@@ -19245,7 +19262,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1924519262 pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
1924619263
1924719264 pm_parser_scope_pop(parser);
19248- expect1 (parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM);
19265+ expect1_opening (parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword );
1924919266
1925019267 if (context_def_p(parser)) {
1925119268 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
@@ -19311,7 +19328,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1931119328 }
1931219329
1931319330 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false);
19314- expect1 (parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM);
19331+ expect1_opening (parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword );
1931519332
1931619333 return UP(pm_until_node_create(parser, &keyword, &do_keyword, &parser->previous, predicate, statements, 0));
1931719334 }
@@ -19345,7 +19362,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1934519362 }
1934619363
1934719364 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false);
19348- expect1 (parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM);
19365+ expect1_opening (parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword );
1934919366
1935019367 return UP(pm_while_node_create(parser, &keyword, &do_keyword, &parser->previous, predicate, statements, 0));
1935119368 }
@@ -20091,7 +20108,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
2009120108 }
2009220109
2009320110 parser_warn_indentation_mismatch(parser, opening_newline_index, &operator, false, false);
20094- expect1 (parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE);
20111+ expect1_opening (parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening );
2009520112 } else {
2009620113 expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
2009720114 opening = parser->previous;
@@ -20109,7 +20126,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
2010920126 parser_warn_indentation_mismatch(parser, opening_newline_index, &operator, false, false);
2011020127 }
2011120128
20112- expect1 (parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END);
20129+ expect1_opening (parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &operator );
2011320130 }
2011420131
2011520132 pm_constant_id_list_t locals;
0 commit comments