diff --git a/prism/extension.c b/prism/extension.c index b7c59e514e..416e682f76 100644 --- a/prism/extension.c +++ b/prism/extension.c @@ -987,12 +987,12 @@ inspect_node(VALUE self, VALUE source) { /** * call-seq: - * Debug::format_errors(source) -> String + * Debug::format_errors(source, colorize) -> String * * Format the errors that are found when parsing the given source string. */ static VALUE -format_errors(VALUE self, VALUE source) { +format_errors(VALUE self, VALUE source, VALUE colorize) { pm_string_t input; input_load_string(&input, source); @@ -1002,7 +1002,7 @@ format_errors(VALUE self, VALUE source) { pm_node_t *node = pm_parse(&parser); pm_buffer_t buffer = { 0 }; - pm_parser_errors_format(&parser, &buffer, true); + pm_parser_errors_format(&parser, &buffer, RTEST(colorize)); rb_encoding *encoding = rb_enc_find(parser.encoding->name); VALUE result = rb_enc_str_new(pm_buffer_value(&buffer), pm_buffer_length(&buffer), encoding); @@ -1093,7 +1093,7 @@ Init_prism(void) { rb_define_singleton_method(rb_cPrismDebug, "memsize", memsize, 1); rb_define_singleton_method(rb_cPrismDebug, "profile_file", profile_file, 1); rb_define_singleton_method(rb_cPrismDebug, "inspect_node", inspect_node, 1); - rb_define_singleton_method(rb_cPrismDebug, "format_errors", format_errors, 1); + rb_define_singleton_method(rb_cPrismDebug, "format_errors", format_errors, 2); // Next, initialize the other APIs. Init_prism_api_node(); diff --git a/prism/prism.c b/prism/prism.c index a078100e3b..4a6797896b 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -17873,7 +17873,7 @@ pm_parser_errors_format_sort(const pm_list_t *error_list, const pm_newline_list_ if (start.line == end.line) { column_end = (uint32_t) end.column; } else { - column_end = (uint32_t) (newline_list->offsets[start.line + 1] - newline_list->offsets[start.line] - 1); + column_end = (uint32_t) (newline_list->offsets[start.line] - newline_list->offsets[start.line - 1] - 1); } // Ensure we have at least one column of error. @@ -17892,16 +17892,16 @@ pm_parser_errors_format_sort(const pm_list_t *error_list, const pm_newline_list_ static inline void pm_parser_errors_format_line(const pm_parser_t *parser, const pm_newline_list_t *newline_list, const char *number_prefix, size_t line, pm_buffer_t *buffer) { - const uint8_t *start = &parser->start[newline_list->offsets[line]]; + const uint8_t *start = &parser->start[newline_list->offsets[line - 1]]; const uint8_t *end; - if (line + 1 >= newline_list->size) { + if (line >= newline_list->size) { end = parser->end; } else { - end = &parser->start[newline_list->offsets[line + 1]]; + end = &parser->start[newline_list->offsets[line]]; } - pm_buffer_append_format(buffer, number_prefix, (uint32_t) (line + 1)); + pm_buffer_append_format(buffer, number_prefix, (uint32_t) line); pm_buffer_append_string(buffer, (const char *) start, (size_t) (end - start)); if (end == parser->end && end[-1] != '\n') { @@ -17926,7 +17926,7 @@ pm_parser_errors_format(const pm_parser_t *parser, pm_buffer_t *buffer, bool col // blank lines based on the maximum number of digits in the line numbers // that are going to be displayed. pm_error_format_t error_format; - size_t max_line_number = errors[error_list->size - 1].line + 1; + size_t max_line_number = errors[error_list->size - 1].line; if (max_line_number < 10) { if (colorize) { @@ -18008,7 +18008,7 @@ pm_parser_errors_format(const pm_parser_t *parser, pm_buffer_t *buffer, bool col // the source before the error to give some context. We'll be careful not to // display the same line twice in case the errors are close enough in the // source. - uint32_t last_line = (uint32_t) -1; + uint32_t last_line = 0; const pm_encoding_t *encoding = parser->encoding; for (size_t index = 0; index < error_list->size; index++) { @@ -18054,7 +18054,7 @@ pm_parser_errors_format(const pm_parser_t *parser, pm_buffer_t *buffer, bool col pm_buffer_append_string(buffer, error_format.blank_prefix, error_format.blank_prefix_length); size_t column = 0; - const uint8_t *start = &parser->start[newline_list->offsets[error->line]]; + const uint8_t *start = &parser->start[newline_list->offsets[error->line - 1]]; while (column < error->column_end) { if (column < error->column_start) { @@ -18078,7 +18078,7 @@ pm_parser_errors_format(const pm_parser_t *parser, pm_buffer_t *buffer, bool col // Here we determine how many lines of padding to display after the // error, depending on where the next error is in source. last_line = error->line; - size_t next_line = (index == error_list->size - 1) ? newline_list->size - 1 : errors[index + 1].line; + size_t next_line = (index == error_list->size - 1) ? newline_list->size : errors[index + 1].line; if (next_line - last_line > 1) { pm_buffer_append_string(buffer, " ", 2); diff --git a/prism/templates/src/prettyprint.c.erb b/prism/templates/src/prettyprint.c.erb index 02b89758b8..605795b64a 100644 --- a/prism/templates/src/prettyprint.c.erb +++ b/prism/templates/src/prettyprint.c.erb @@ -40,7 +40,7 @@ static inline void prettyprint_location(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_location_t *location) { pm_line_column_t start = pm_newline_list_line_column(&parser->newline_list, location->start); pm_line_column_t end = pm_newline_list_line_column(&parser->newline_list, location->end); - pm_buffer_append_format(output_buffer, "(%lu,%lu)-(%lu,%lu)", (unsigned long) (start.line + 1), (unsigned long) start.column, (unsigned long) (end.line + 1), (unsigned long) end.column); + pm_buffer_append_format(output_buffer, "(%lu,%lu)-(%lu,%lu)", (unsigned long) start.line, (unsigned long) start.column, (unsigned long) end.line, (unsigned long) end.column); } static inline void diff --git a/prism/util/pm_newline_list.c b/prism/util/pm_newline_list.c index 32a4a050fe..724d840dd2 100644 --- a/prism/util/pm_newline_list.c +++ b/prism/util/pm_newline_list.c @@ -62,7 +62,7 @@ pm_newline_list_line_column(const pm_newline_list_t *list, const uint8_t *cursor size_t mid = left + (right - left) / 2; if (list->offsets[mid] == offset) { - return ((pm_line_column_t) { mid, 0 }); + return ((pm_line_column_t) { mid + 1, 0 }); } if (list->offsets[mid] < offset) { @@ -72,7 +72,7 @@ pm_newline_list_line_column(const pm_newline_list_t *list, const uint8_t *cursor } } - return ((pm_line_column_t) { left - 1, offset - list->offsets[left - 1] }); + return ((pm_line_column_t) { left, offset - list->offsets[left - 1] }); } /** diff --git a/test/prism/format_errors_test.rb b/test/prism/format_errors_test.rb new file mode 100644 index 0000000000..62b24723b8 --- /dev/null +++ b/test/prism/format_errors_test.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +return if Prism::BACKEND == :FFI + +require_relative "test_helper" + +module Prism + class FormatErrorsTest < TestCase + def test_format_errors + assert_equal <<~ERROR, Debug.format_errors("<>", false) + > 1 | <> + | ^ cannot parse the expression + | ^ cannot parse the expression + ERROR + end + end +end