From 166764f7942f1baa9d3709a1f9eb625724e200dc Mon Sep 17 00:00:00 2001 From: Thomas Marshall Date: Mon, 29 Dec 2025 12:54:28 +0000 Subject: [PATCH 1/2] Add unterminated construct tests --- test/prism/errors/unterminated_begin.txt | 4 ++++ test/prism/errors/unterminated_begin_upcase.txt | 4 ++++ test/prism/errors/unterminated_block_do_end.txt | 4 ++++ test/prism/errors/unterminated_class.txt | 4 ++++ test/prism/errors/unterminated_def.txt | 5 +++++ test/prism/errors/unterminated_end_upcase.txt | 4 ++++ test/prism/errors/unterminated_for.txt | 5 +++++ test/prism/errors/unterminated_if.txt | 5 +++++ test/prism/errors/unterminated_if_else.txt | 5 +++++ test/prism/errors/unterminated_lambda_brace.txt | 4 ++++ test/prism/errors/unterminated_module.txt | 4 ++++ test/prism/errors/unterminated_pattern_bracket.txt | 7 +++++++ test/prism/errors/unterminated_pattern_paren.txt | 7 +++++++ test/prism/errors/unterminated_until.txt | 5 +++++ 14 files changed, 67 insertions(+) create mode 100644 test/prism/errors/unterminated_begin.txt create mode 100644 test/prism/errors/unterminated_begin_upcase.txt create mode 100644 test/prism/errors/unterminated_block_do_end.txt create mode 100644 test/prism/errors/unterminated_class.txt create mode 100644 test/prism/errors/unterminated_def.txt create mode 100644 test/prism/errors/unterminated_end_upcase.txt create mode 100644 test/prism/errors/unterminated_for.txt create mode 100644 test/prism/errors/unterminated_if.txt create mode 100644 test/prism/errors/unterminated_if_else.txt create mode 100644 test/prism/errors/unterminated_lambda_brace.txt create mode 100644 test/prism/errors/unterminated_module.txt create mode 100644 test/prism/errors/unterminated_pattern_bracket.txt create mode 100644 test/prism/errors/unterminated_pattern_paren.txt create mode 100644 test/prism/errors/unterminated_until.txt diff --git a/test/prism/errors/unterminated_begin.txt b/test/prism/errors/unterminated_begin.txt new file mode 100644 index 0000000000..6217f80a0b --- /dev/null +++ b/test/prism/errors/unterminated_begin.txt @@ -0,0 +1,4 @@ +begin + ^ unexpected end-of-input, assuming it is closing the parent top level context + ^ expected an `end` to close the `begin` statement + diff --git a/test/prism/errors/unterminated_begin_upcase.txt b/test/prism/errors/unterminated_begin_upcase.txt new file mode 100644 index 0000000000..92b975bf76 --- /dev/null +++ b/test/prism/errors/unterminated_begin_upcase.txt @@ -0,0 +1,4 @@ +BEGIN { + ^ unexpected end-of-input, assuming it is closing the parent top level context + ^ expected a `}` to close the `BEGIN` statement + diff --git a/test/prism/errors/unterminated_block_do_end.txt b/test/prism/errors/unterminated_block_do_end.txt new file mode 100644 index 0000000000..fb7ca53d6a --- /dev/null +++ b/test/prism/errors/unterminated_block_do_end.txt @@ -0,0 +1,4 @@ +foo do + ^ unexpected end-of-input, assuming it is closing the parent top level context + ^ expected a block beginning with `do` to end with `end` + diff --git a/test/prism/errors/unterminated_class.txt b/test/prism/errors/unterminated_class.txt new file mode 100644 index 0000000000..ea80ab8fc7 --- /dev/null +++ b/test/prism/errors/unterminated_class.txt @@ -0,0 +1,4 @@ +class Foo + ^ unexpected end-of-input, assuming it is closing the parent top level context + ^ expected an `end` to close the `class` statement + diff --git a/test/prism/errors/unterminated_def.txt b/test/prism/errors/unterminated_def.txt new file mode 100644 index 0000000000..83ec939fea --- /dev/null +++ b/test/prism/errors/unterminated_def.txt @@ -0,0 +1,5 @@ +def foo + ^ expected a delimiter to close the parameters + ^ unexpected end-of-input, assuming it is closing the parent top level context + ^ expected an `end` to close the `def` statement + diff --git a/test/prism/errors/unterminated_end_upcase.txt b/test/prism/errors/unterminated_end_upcase.txt new file mode 100644 index 0000000000..42ccd22bd5 --- /dev/null +++ b/test/prism/errors/unterminated_end_upcase.txt @@ -0,0 +1,4 @@ +END { + ^ unexpected end-of-input, assuming it is closing the parent top level context + ^ expected a `}` to close the `END` statement + diff --git a/test/prism/errors/unterminated_for.txt b/test/prism/errors/unterminated_for.txt new file mode 100644 index 0000000000..cbd17f0b84 --- /dev/null +++ b/test/prism/errors/unterminated_for.txt @@ -0,0 +1,5 @@ +for x in y + ^ unexpected end-of-input; expected a 'do', newline, or ';' after the 'for' loop collection + ^ unexpected end-of-input, assuming it is closing the parent top level context + ^ expected an `end` to close the `for` loop + diff --git a/test/prism/errors/unterminated_if.txt b/test/prism/errors/unterminated_if.txt new file mode 100644 index 0000000000..559a006022 --- /dev/null +++ b/test/prism/errors/unterminated_if.txt @@ -0,0 +1,5 @@ +if true + ^ expected `then` or `;` or '\n' + ^ unexpected end-of-input, assuming it is closing the parent top level context + ^ expected an `end` to close the conditional clause + diff --git a/test/prism/errors/unterminated_if_else.txt b/test/prism/errors/unterminated_if_else.txt new file mode 100644 index 0000000000..35a181e844 --- /dev/null +++ b/test/prism/errors/unterminated_if_else.txt @@ -0,0 +1,5 @@ +if true +else + ^ unexpected end-of-input, assuming it is closing the parent top level context + ^ expected an `end` to close the `else` clause + diff --git a/test/prism/errors/unterminated_lambda_brace.txt b/test/prism/errors/unterminated_lambda_brace.txt new file mode 100644 index 0000000000..bb8c1090ab --- /dev/null +++ b/test/prism/errors/unterminated_lambda_brace.txt @@ -0,0 +1,4 @@ +-> { + ^ unexpected end-of-input, assuming it is closing the parent top level context + ^ expected a lambda block beginning with `{` to end with `}` + diff --git a/test/prism/errors/unterminated_module.txt b/test/prism/errors/unterminated_module.txt new file mode 100644 index 0000000000..cf207c06a7 --- /dev/null +++ b/test/prism/errors/unterminated_module.txt @@ -0,0 +1,4 @@ +module Foo + ^ unexpected end-of-input, assuming it is closing the parent top level context + ^ expected an `end` to close the `module` statement + diff --git a/test/prism/errors/unterminated_pattern_bracket.txt b/test/prism/errors/unterminated_pattern_bracket.txt new file mode 100644 index 0000000000..cc2630f8e9 --- /dev/null +++ b/test/prism/errors/unterminated_pattern_bracket.txt @@ -0,0 +1,7 @@ +case x +in [1 + ^ expected a `]` to close the pattern expression + ^ expected a delimiter after the patterns of an `in` clause + ^ unexpected end-of-input, assuming it is closing the parent top level context + ^ expected an `end` to close the `case` statement + diff --git a/test/prism/errors/unterminated_pattern_paren.txt b/test/prism/errors/unterminated_pattern_paren.txt new file mode 100644 index 0000000000..162a128546 --- /dev/null +++ b/test/prism/errors/unterminated_pattern_paren.txt @@ -0,0 +1,7 @@ +case x +in (1 + ^ expected a `)` to close the pattern expression + ^ expected a delimiter after the patterns of an `in` clause + ^ unexpected end-of-input, assuming it is closing the parent top level context + ^ expected an `end` to close the `case` statement + diff --git a/test/prism/errors/unterminated_until.txt b/test/prism/errors/unterminated_until.txt new file mode 100644 index 0000000000..b9d7eee40f --- /dev/null +++ b/test/prism/errors/unterminated_until.txt @@ -0,0 +1,5 @@ +until true + ^ expected a predicate expression for the `until` statement + ^ unexpected end-of-input, assuming it is closing the parent top level context + ^ expected an `end` to close the `until` statement + From 2d7829f060763acdb341cd17ab2c236e40abf4d7 Mon Sep 17 00:00:00 2001 From: Thomas Marshall Date: Mon, 29 Dec 2025 12:55:18 +0000 Subject: [PATCH 2/2] Report missing end errors at opening token This commit adds an `expect1_opening` function that expects a token and attaches the error to the opening token location rather than the current position. This is useful for errors about missing closing tokens, where we want to point to the line with the opening token rather than the end of the file. For example: ```ruby def foo def bar def baz ^ expected an `end` to close the `def` statement ^ expected an `end` to close the `def` statement ^ expected an `end` to close the `def` statement ``` This would previously produce three identical errors at the end of the file. After this commit, they would be reported at the opening token location: ```ruby def foo ^~~ expected an `end` to close the `def` statement def bar ^~~ expected an `end` to close the `def` statement def baz ^~~ expected an `end` to close the `def` statement ``` I considered using the end of the line where the opening token is located, but in some cases that would be less useful than the opening token location itself. For example: ```ruby def foo def bar def baz ``` Here the end of the line where the opening token is located would be the same for each of the unclosed `def` nodes. --- src/prism.c | 67 ++++++++++++------- ...ginning_with_brace_and_ending_with_end.txt | 2 +- test/prism/errors/command_calls_2.txt | 2 +- test/prism/errors/command_calls_24.txt | 2 +- test/prism/errors/command_calls_25.txt | 2 +- test/prism/errors/heredoc_unterminated.txt | 2 +- test/prism/errors/infix_after_label.txt | 2 +- .../errors/label_in_interpolated_string.txt | 2 +- test/prism/errors/pattern_string_key.txt | 2 +- test/prism/errors/shadow_args_in_lambda.txt | 2 +- test/prism/errors/unterminated_begin.txt | 2 +- .../errors/unterminated_begin_upcase.txt | 2 +- test/prism/errors/unterminated_block.txt | 2 +- .../errors/unterminated_block_do_end.txt | 2 +- test/prism/errors/unterminated_class.txt | 2 +- test/prism/errors/unterminated_def.txt | 2 +- test/prism/errors/unterminated_end_upcase.txt | 2 +- test/prism/errors/unterminated_for.txt | 2 +- test/prism/errors/unterminated_if.txt | 2 +- test/prism/errors/unterminated_if_else.txt | 2 +- .../errors/unterminated_lambda_brace.txt | 2 +- test/prism/errors/unterminated_module.txt | 2 +- .../errors/unterminated_pattern_bracket.txt | 4 +- .../errors/unterminated_pattern_paren.txt | 4 +- test/prism/errors/unterminated_until.txt | 2 +- test/prism/errors/while_endless_method.txt | 2 +- 26 files changed, 69 insertions(+), 52 deletions(-) diff --git a/src/prism.c b/src/prism.c index 4c8ab91f0e..1a8cdf7568 100644 --- a/src/prism.c +++ b/src/prism.c @@ -12422,6 +12422,22 @@ expect1_heredoc_term(pm_parser_t *parser, const uint8_t *ident_start, size_t ide } } +/** + * A special expect1 that attaches the error to the opening token location + * rather than the current position. This is useful for errors about missing + * closing tokens, where we want to point to the line with the opening token + * (e.g., `def`, `class`, `if`, `{`) rather than the end of the file. + */ +static void +expect1_opening(pm_parser_t *parser, pm_token_type_t type, pm_diagnostic_id_t diag_id, const pm_token_t *opening) { + if (accept1(parser, type)) return; + + pm_parser_err(parser, opening->start, opening->end, diag_id); + + parser->previous.start = opening->end; + parser->previous.type = PM_TOKEN_MISSING; +} + static pm_node_t * parse_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); @@ -14764,7 +14780,7 @@ parse_block(pm_parser_t *parser, uint16_t depth) { statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_BRACES, (uint16_t) (depth + 1))); } - expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE); + expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE, &opening); } else { if (!match1(parser, PM_TOKEN_KEYWORD_END)) { 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) { } } - expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END); + expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END, &opening); } pm_constant_id_list_t locals; @@ -15204,7 +15220,7 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword, false, false); - expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE); + expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword); pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->previous); @@ -15221,7 +15237,7 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl } } else { parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else, false); - expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM); + expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword); } // 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 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) { inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1)); accept1(parser, PM_TOKEN_NEWLINE); - expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET); + expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening); } closing = parser->previous; @@ -16214,7 +16230,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) { inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1)); accept1(parser, PM_TOKEN_NEWLINE); - expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN); + expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening); } closing = parser->previous; @@ -16594,7 +16610,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1)); accept1(parser, PM_TOKEN_NEWLINE); - expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET); + expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening); pm_token_t closing = parser->previous; switch (PM_NODE_TYPE(inner)) { @@ -16672,7 +16688,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1)); accept1(parser, PM_TOKEN_NEWLINE); - expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE); + expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening); pm_token_t closing = parser->previous; node->base.location.start = opening.start; @@ -16798,7 +16814,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm parser->pattern_matching_newlines = previous_pattern_matching_newlines; accept1(parser, PM_TOKEN_NEWLINE); - expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN); + expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen); return UP(pm_pinned_expression_node_create(parser, expression, &operator, &lparen, &parser->previous)); } default: { @@ -16896,7 +16912,7 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1)); accept1(parser, PM_TOKEN_NEWLINE); - expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN); + expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening); pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->previous, 0)); if (!alternation) { @@ -17748,7 +17764,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_accepts_block_stack_push(parser, true); parser_lex(parser); - pm_hash_node_t *node = pm_hash_node_create(parser, &parser->previous); + pm_token_t opening = parser->previous; + pm_hash_node_t *node = pm_hash_node_create(parser, &opening); if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) { if (current_hash_keys != NULL) { @@ -17763,7 +17780,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } pm_accepts_block_stack_pop(parser); - expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM); + expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening); pm_hash_node_closing_loc_set(node, &parser->previous); return UP(node); @@ -18380,7 +18397,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, false); - expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM); + expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword); if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) { 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 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements); parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1)); - expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM); + expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword); begin_node->base.location.end = parser->previous.end; 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 pm_token_t opening = parser->previous; pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_PREEXE, (uint16_t) (depth + 1)); - expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM); + expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening); pm_context_t context = parser->current_context->context; if ((context != PM_CONTEXT_MAIN) && (context != PM_CONTEXT_PREEXE)) { 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 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword, false, false); } - expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM); + expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword); pm_constant_id_list_t locals; 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 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword, false, false); } - expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM); + expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword); if (context_def_p(parser)) { 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 pm_accepts_block_stack_pop(parser); pm_do_loop_stack_pop(parser); - expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM); + expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword); end_keyword = parser->previous; } @@ -19030,7 +19047,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_token_t opening = parser->previous; pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_POSTEXE, (uint16_t) (depth + 1)); - expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM); + expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening); return UP(pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->previous)); } case PM_TOKEN_KEYWORD_FALSE: @@ -19094,7 +19111,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword, false, false); - expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM); + expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword); return UP(pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->previous)); } @@ -19245,7 +19262,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_locals_order(parser, &parser->current_scope->locals, &locals, false); pm_parser_scope_pop(parser); - expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM); + expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword); if (context_def_p(parser)) { 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 } parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false); - expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM); + expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword); return UP(pm_until_node_create(parser, &keyword, &do_keyword, &parser->previous, predicate, statements, 0)); } @@ -19345,7 +19362,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false); - expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM); + expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword); return UP(pm_while_node_create(parser, &keyword, &do_keyword, &parser->previous, predicate, statements, 0)); } @@ -20091,7 +20108,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } parser_warn_indentation_mismatch(parser, opening_newline_index, &operator, false, false); - expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE); + expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening); } else { expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN); opening = parser->previous; @@ -20109,7 +20126,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser_warn_indentation_mismatch(parser, opening_newline_index, &operator, false, false); } - expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END); + expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &operator); } pm_constant_id_list_t locals; diff --git a/test/prism/errors/block_beginning_with_brace_and_ending_with_end.txt b/test/prism/errors/block_beginning_with_brace_and_ending_with_end.txt index 16af8200ec..1184b38ce8 100644 --- a/test/prism/errors/block_beginning_with_brace_and_ending_with_end.txt +++ b/test/prism/errors/block_beginning_with_brace_and_ending_with_end.txt @@ -1,5 +1,5 @@ x.each { x end ^~~ unexpected 'end', expecting end-of-input ^~~ unexpected 'end', ignoring it - ^ expected a block beginning with `{` to end with `}` + ^ expected a block beginning with `{` to end with `}` diff --git a/test/prism/errors/command_calls_2.txt b/test/prism/errors/command_calls_2.txt index b0983c015b..13e10f7ebf 100644 --- a/test/prism/errors/command_calls_2.txt +++ b/test/prism/errors/command_calls_2.txt @@ -1,5 +1,5 @@ {a: b c} - ^ expected a `}` to close the hash literal +^ expected a `}` to close the hash literal ^ unexpected local variable or method, expecting end-of-input ^ unexpected '}', expecting end-of-input ^ unexpected '}', ignoring it diff --git a/test/prism/errors/command_calls_24.txt b/test/prism/errors/command_calls_24.txt index 3046b36dc1..27a32ea3bf 100644 --- a/test/prism/errors/command_calls_24.txt +++ b/test/prism/errors/command_calls_24.txt @@ -1,5 +1,5 @@ ->a=b c{} ^ expected a `do` keyword or a `{` to open the lambda block ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected a lambda block beginning with `do` to end with `end` +^~ expected a lambda block beginning with `do` to end with `end` diff --git a/test/prism/errors/command_calls_25.txt b/test/prism/errors/command_calls_25.txt index 5fddd90fdd..cf04508f87 100644 --- a/test/prism/errors/command_calls_25.txt +++ b/test/prism/errors/command_calls_25.txt @@ -4,5 +4,5 @@ ^ unexpected ')', expecting end-of-input ^ unexpected ')', ignoring it ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected a lambda block beginning with `do` to end with `end` +^~ expected a lambda block beginning with `do` to end with `end` diff --git a/test/prism/errors/heredoc_unterminated.txt b/test/prism/errors/heredoc_unterminated.txt index 3c6aeaeb81..56bd162998 100644 --- a/test/prism/errors/heredoc_unterminated.txt +++ b/test/prism/errors/heredoc_unterminated.txt @@ -3,7 +3,7 @@ a=>{< 1 } ^ unexpected '.'; expected a value in the hash literal - ^ expected a `}` to close the hash literal +^ expected a `}` to close the hash literal ^ unexpected '}', expecting end-of-input ^ unexpected '}', ignoring it diff --git a/test/prism/errors/label_in_interpolated_string.txt b/test/prism/errors/label_in_interpolated_string.txt index e8f40dd2a8..29af5310a1 100644 --- a/test/prism/errors/label_in_interpolated_string.txt +++ b/test/prism/errors/label_in_interpolated_string.txt @@ -2,6 +2,7 @@ case in el""Q ^~~~ expected a predicate for a case matching statement ^ expected a delimiter after the patterns of an `in` clause ^ unexpected constant, expecting end-of-input +^~~~ expected an `end` to close the `case` statement !"""#{in el"":Q ^~ unexpected 'in', assuming it is closing the parent 'in' clause ^ expected a `}` to close the embedded expression @@ -10,5 +11,4 @@ case in el""Q ^ cannot parse the string part ^~~~~~~~~~~ unexpected label ^~~~~~~~~~~ expected a string for concatenation - ^ expected an `end` to close the `case` statement diff --git a/test/prism/errors/pattern_string_key.txt b/test/prism/errors/pattern_string_key.txt index 9f28feddb9..41bc1fa57b 100644 --- a/test/prism/errors/pattern_string_key.txt +++ b/test/prism/errors/pattern_string_key.txt @@ -1,8 +1,8 @@ case:a +^~~~ expected an `end` to close the `case` statement in b:"","#{}" ^~~~~ expected a label after the `,` in the hash pattern ^ expected a pattern expression after the key ^ expected a delimiter after the patterns of an `in` clause ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected an `end` to close the `case` statement diff --git a/test/prism/errors/shadow_args_in_lambda.txt b/test/prism/errors/shadow_args_in_lambda.txt index 2399a0ebd5..7fc78d7d8f 100644 --- a/test/prism/errors/shadow_args_in_lambda.txt +++ b/test/prism/errors/shadow_args_in_lambda.txt @@ -1,5 +1,5 @@ ->a;b{} ^ expected a `do` keyword or a `{` to open the lambda block ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected a lambda block beginning with `do` to end with `end` +^~ expected a lambda block beginning with `do` to end with `end` diff --git a/test/prism/errors/unterminated_begin.txt b/test/prism/errors/unterminated_begin.txt index 6217f80a0b..2733f830c9 100644 --- a/test/prism/errors/unterminated_begin.txt +++ b/test/prism/errors/unterminated_begin.txt @@ -1,4 +1,4 @@ begin ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected an `end` to close the `begin` statement +^~~~~ expected an `end` to close the `begin` statement diff --git a/test/prism/errors/unterminated_begin_upcase.txt b/test/prism/errors/unterminated_begin_upcase.txt index 92b975bf76..5512f2089e 100644 --- a/test/prism/errors/unterminated_begin_upcase.txt +++ b/test/prism/errors/unterminated_begin_upcase.txt @@ -1,4 +1,4 @@ BEGIN { ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected a `}` to close the `BEGIN` statement + ^ expected a `}` to close the `BEGIN` statement diff --git a/test/prism/errors/unterminated_block.txt b/test/prism/errors/unterminated_block.txt index 8cc772db16..db6a4aa56c 100644 --- a/test/prism/errors/unterminated_block.txt +++ b/test/prism/errors/unterminated_block.txt @@ -1,4 +1,4 @@ foo { ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected a block beginning with `{` to end with `}` + ^ expected a block beginning with `{` to end with `}` diff --git a/test/prism/errors/unterminated_block_do_end.txt b/test/prism/errors/unterminated_block_do_end.txt index fb7ca53d6a..0b7c64965f 100644 --- a/test/prism/errors/unterminated_block_do_end.txt +++ b/test/prism/errors/unterminated_block_do_end.txt @@ -1,4 +1,4 @@ foo do ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected a block beginning with `do` to end with `end` + ^~ expected a block beginning with `do` to end with `end` diff --git a/test/prism/errors/unterminated_class.txt b/test/prism/errors/unterminated_class.txt index ea80ab8fc7..f47a3aa7df 100644 --- a/test/prism/errors/unterminated_class.txt +++ b/test/prism/errors/unterminated_class.txt @@ -1,4 +1,4 @@ class Foo ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected an `end` to close the `class` statement +^~~~~ expected an `end` to close the `class` statement diff --git a/test/prism/errors/unterminated_def.txt b/test/prism/errors/unterminated_def.txt index 83ec939fea..a6212e3a21 100644 --- a/test/prism/errors/unterminated_def.txt +++ b/test/prism/errors/unterminated_def.txt @@ -1,5 +1,5 @@ def foo ^ expected a delimiter to close the parameters ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected an `end` to close the `def` statement +^~~ expected an `end` to close the `def` statement diff --git a/test/prism/errors/unterminated_end_upcase.txt b/test/prism/errors/unterminated_end_upcase.txt index 42ccd22bd5..ef01caa0ca 100644 --- a/test/prism/errors/unterminated_end_upcase.txt +++ b/test/prism/errors/unterminated_end_upcase.txt @@ -1,4 +1,4 @@ END { ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected a `}` to close the `END` statement + ^ expected a `}` to close the `END` statement diff --git a/test/prism/errors/unterminated_for.txt b/test/prism/errors/unterminated_for.txt index cbd17f0b84..75978a7cae 100644 --- a/test/prism/errors/unterminated_for.txt +++ b/test/prism/errors/unterminated_for.txt @@ -1,5 +1,5 @@ for x in y ^ unexpected end-of-input; expected a 'do', newline, or ';' after the 'for' loop collection ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected an `end` to close the `for` loop +^~~ expected an `end` to close the `for` loop diff --git a/test/prism/errors/unterminated_if.txt b/test/prism/errors/unterminated_if.txt index 559a006022..1697931773 100644 --- a/test/prism/errors/unterminated_if.txt +++ b/test/prism/errors/unterminated_if.txt @@ -1,5 +1,5 @@ if true ^ expected `then` or `;` or '\n' ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected an `end` to close the conditional clause +^~ expected an `end` to close the conditional clause diff --git a/test/prism/errors/unterminated_if_else.txt b/test/prism/errors/unterminated_if_else.txt index 35a181e844..db7828cce8 100644 --- a/test/prism/errors/unterminated_if_else.txt +++ b/test/prism/errors/unterminated_if_else.txt @@ -1,5 +1,5 @@ if true +^~ expected an `end` to close the `else` clause else ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected an `end` to close the `else` clause diff --git a/test/prism/errors/unterminated_lambda_brace.txt b/test/prism/errors/unterminated_lambda_brace.txt index bb8c1090ab..75474c7534 100644 --- a/test/prism/errors/unterminated_lambda_brace.txt +++ b/test/prism/errors/unterminated_lambda_brace.txt @@ -1,4 +1,4 @@ -> { ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected a lambda block beginning with `{` to end with `}` + ^ expected a lambda block beginning with `{` to end with `}` diff --git a/test/prism/errors/unterminated_module.txt b/test/prism/errors/unterminated_module.txt index cf207c06a7..4c50ba5f63 100644 --- a/test/prism/errors/unterminated_module.txt +++ b/test/prism/errors/unterminated_module.txt @@ -1,4 +1,4 @@ module Foo ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected an `end` to close the `module` statement +^~~~~~ expected an `end` to close the `module` statement diff --git a/test/prism/errors/unterminated_pattern_bracket.txt b/test/prism/errors/unterminated_pattern_bracket.txt index cc2630f8e9..4f35cd84af 100644 --- a/test/prism/errors/unterminated_pattern_bracket.txt +++ b/test/prism/errors/unterminated_pattern_bracket.txt @@ -1,7 +1,7 @@ case x +^~~~ expected an `end` to close the `case` statement in [1 - ^ expected a `]` to close the pattern expression + ^ expected a `]` to close the pattern expression ^ expected a delimiter after the patterns of an `in` clause ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected an `end` to close the `case` statement diff --git a/test/prism/errors/unterminated_pattern_paren.txt b/test/prism/errors/unterminated_pattern_paren.txt index 162a128546..426d614e61 100644 --- a/test/prism/errors/unterminated_pattern_paren.txt +++ b/test/prism/errors/unterminated_pattern_paren.txt @@ -1,7 +1,7 @@ case x +^~~~ expected an `end` to close the `case` statement in (1 - ^ expected a `)` to close the pattern expression + ^ expected a `)` to close the pattern expression ^ expected a delimiter after the patterns of an `in` clause ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected an `end` to close the `case` statement diff --git a/test/prism/errors/unterminated_until.txt b/test/prism/errors/unterminated_until.txt index b9d7eee40f..42a0545200 100644 --- a/test/prism/errors/unterminated_until.txt +++ b/test/prism/errors/unterminated_until.txt @@ -1,5 +1,5 @@ until true ^ expected a predicate expression for the `until` statement ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected an `end` to close the `until` statement +^~~~~ expected an `end` to close the `until` statement diff --git a/test/prism/errors/while_endless_method.txt b/test/prism/errors/while_endless_method.txt index 6f062d89d0..cdd7ba9aba 100644 --- a/test/prism/errors/while_endless_method.txt +++ b/test/prism/errors/while_endless_method.txt @@ -1,5 +1,5 @@ while def f = g do end ^ expected a predicate expression for the `while` statement ^ unexpected end-of-input, assuming it is closing the parent top level context - ^ expected an `end` to close the `while` statement +^~~~~ expected an `end` to close the `while` statement