From 944855ca185f4d6a1587c174752446752775e040 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Tue, 1 Jun 2021 23:05:27 +0430 Subject: [PATCH] AK+Everywhere: Fix compiletime format parsing of replacement fields --- AK/CheckedFormatString.h | 11 ++++++++--- Tests/AK/TestFormat.cpp | 10 +++++----- Userland/Shell/Shell.cpp | 8 ++++---- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/AK/CheckedFormatString.h b/AK/CheckedFormatString.h index 87d351f2dc1..b08e4d12ade 100644 --- a/AK/CheckedFormatString.h +++ b/AK/CheckedFormatString.h @@ -79,6 +79,7 @@ consteval auto count_fmt_params(const char (&fmt)[N]) size_t unclosed_braces { 0 }; size_t extra_closed_braces { 0 }; + size_t nesting_level { 0 }; Array last_format_specifier_start { 0 }; size_t total_used_last_format_specifier_start_count { 0 }; @@ -100,13 +101,17 @@ consteval auto count_fmt_params(const char (&fmt)[N]) result.last_format_specifier_start[result.total_used_last_format_specifier_start_count++] = i + 1; ++result.unclosed_braces; + ++result.nesting_level; break; case '}': - if (i + 1 < N && fmt[i + 1] == '}') { - ++i; - continue; + if (result.nesting_level == 0) { + if (i + 1 < N && fmt[i + 1] == '}') { + ++i; + continue; + } } if (result.unclosed_braces) { + --result.nesting_level; --result.unclosed_braces; if (result.total_used_last_format_specifier_start_count == 0) diff --git a/Tests/AK/TestFormat.cpp b/Tests/AK/TestFormat.cpp index 237d1a43540..266185a9d91 100644 --- a/Tests/AK/TestFormat.cpp +++ b/Tests/AK/TestFormat.cpp @@ -105,12 +105,12 @@ TEST_CASE(zero_pad) TEST_CASE(replacement_field) { - // FIXME: Compiletime check bypass: cannot parse '}}' correctly. - EXPECT_EQ(String::formatted(StringView { "{:*>{1}}" }, 13, static_cast(10)), "********13"); - EXPECT_EQ(String::formatted(StringView { "{:*<{1}}" }, 7, 4), "7***"); + EXPECT_EQ(String::formatted("{:*>{1}}", 13, static_cast(10)), "********13"); + EXPECT_EQ(String::formatted("{:*<{1}}", 7, 4), "7***"); + // Compiletime check bypass: intentionally ignoring extra arguments EXPECT_EQ(String::formatted(StringView { "{:{2}}" }, -5, 8, 16), " -5"); - EXPECT_EQ(String::formatted(StringView { "{{{:*^{1}}}}" }, 1, 3), "{*1*}"); - EXPECT_EQ(String::formatted(StringView { "{:0{}}" }, 1, 3), "001"); + EXPECT_EQ(String::formatted("{{{:*^{1}}}}", 1, 3), "{*1*}"); + EXPECT_EQ(String::formatted("{:0{}}", 1, 3), "001"); } TEST_CASE(replacement_field_regression) diff --git a/Userland/Shell/Shell.cpp b/Userland/Shell/Shell.cpp index 94c7efcc661..aa985d8e7d4 100644 --- a/Userland/Shell/Shell.cpp +++ b/Userland/Shell/Shell.cpp @@ -1998,16 +1998,16 @@ void Shell::possibly_print_error() const warn("\x1b[31m"); size_t length_written_so_far = 0; if (line == (i64)source_position.position->start_line.line_number) { - warn(StringView { "{:~>{}}" }, "", 5 + source_position.position->start_line.line_column); + warn("{:~>{}}", "", 5 + source_position.position->start_line.line_column); length_written_so_far += source_position.position->start_line.line_column; } else { - warn(StringView { "{:~>{}}" }, "", 5); + warn("{:~>{}}", "", 5); } if (line == (i64)source_position.position->end_line.line_number) { - warn(StringView { "{:^>{}}" }, "", source_position.position->end_line.line_column - length_written_so_far); + warn("{:^>{}}", "", source_position.position->end_line.line_column - length_written_so_far); length_written_so_far += source_position.position->start_line.line_column; } else { - warn(StringView { "{:^>{}}" }, "", current_line.length() - length_written_so_far); + warn("{:^>{}}", "", current_line.length() - length_written_so_far); } warnln("\x1b[0m"); }