diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 90bdac1610..6ea4f9c66a 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -481,7 +481,7 @@ namespace Compiler } void GetArgumentsFromMessageFormat::visitedPlaceholder( - Placeholder placeholder, char /*padding*/, int /*width*/, int /*precision*/, Notation /*notation*/) + Placeholder placeholder, int /*flags*/, int /*width*/, int /*precision*/, Notation /*notation*/) { switch (placeholder) { diff --git a/components/compiler/lineparser.hpp b/components/compiler/lineparser.hpp index 68b3198ff2..67ad8e7603 100644 --- a/components/compiler/lineparser.hpp +++ b/components/compiler/lineparser.hpp @@ -88,7 +88,7 @@ namespace Compiler protected: void visitedPlaceholder( - Placeholder placeholder, char padding, int width, int precision, Notation notation) override; + Placeholder placeholder, int flags, int width, int precision, Notation notation) override; void visitedCharacter(char c) override {} public: diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp index 0b49b3c248..c8da745c41 100644 --- a/components/interpreter/miscopcodes.hpp +++ b/components/interpreter/miscopcodes.hpp @@ -2,8 +2,7 @@ #define INTERPRETER_MISCOPCODES_H_INCLUDED #include -#include -#include +#include #include #include @@ -23,78 +22,79 @@ namespace Interpreter protected: void visitedPlaceholder( - Placeholder placeholder, char padding, int width, int precision, Notation notation) override + Placeholder placeholder, int flags, int width, int precision, Notation notation) override { - std::ostringstream out; - out.fill(padding); - if (width != -1) - out.width(width); - if (precision != -1) - out.precision(precision); + std::string formatString; - switch (placeholder) + if (placeholder == StringPlaceholder) { - case StringPlaceholder: - { - int index = mRuntime[0].mInteger; - mRuntime.pop(); + int index = mRuntime[0].mInteger; + mRuntime.pop(); - out << mRuntime.getStringLiteral(index); - mFormattedMessage += out.str(); - } - break; - case IntegerPlaceholder: + std::string_view value = mRuntime.getStringLiteral(index); + if (precision >= 0) + value = value.substr(0, static_cast(precision)); + if (width < 0) + mFormattedMessage += value; + else { - Type_Integer value = mRuntime[0].mInteger; - mRuntime.pop(); - - out << value; - mFormattedMessage += out.str(); + formatString = "{:"; + if (flags & PrependZero) + formatString += '0'; + if (flags & AlignLeft) + formatString += '<'; + else + formatString += '>'; + formatString += "{}}"; + mFormattedMessage += std::vformat(formatString, std::make_format_args(value, width)); } - break; - case FloatPlaceholder: + } + else + { + formatString = "{:"; + if (flags & AlignLeft) + formatString += '<'; + if (flags & PositiveSign) + formatString += '+'; + else if (flags & PositiveSpace) + formatString += ' '; + if (flags & AlternateForm) + formatString += '#'; + if (flags & PrependZero) + formatString += '0'; + if (width >= 0) + formatString += "{}"; + if (placeholder == FloatPlaceholder) + { + if (precision >= 0) + formatString += ".{}"; + formatString += static_cast(notation); + } + else + precision = -1; + formatString += '}'; + const auto appendMessage = [&](auto value) { + if (width >= 0 && precision >= 0) + mFormattedMessage += std::vformat(formatString, std::make_format_args(value, width, precision)); + else if (width >= 0) + mFormattedMessage += std::vformat(formatString, std::make_format_args(value, width)); + else if (precision >= 0) + mFormattedMessage += std::vformat(formatString, std::make_format_args(value, precision)); + else + mFormattedMessage += std::vformat(formatString, std::make_format_args(value)); + }; + if (placeholder == FloatPlaceholder) { float value = mRuntime[0].mFloat; mRuntime.pop(); - - if (notation == Notation::Fixed) - { - out << std::fixed << value; - mFormattedMessage += out.str(); - } - else if (notation == Notation::Shortest) - { - out << value; - std::string standard = out.str(); - - out.str(std::string()); - out.clear(); - - out << std::scientific << value; - std::string scientific = out.str(); - - mFormattedMessage += standard.length() < scientific.length() ? standard : scientific; - } - // TODO switch to std::format so the precision argument applies to these two - else if (notation == Notation::HexLower) - { - out << std::hexfloat << value; - mFormattedMessage += out.str(); - } - else if (notation == Notation::HexUpper) - { - out << std::uppercase << std::hexfloat << value; - mFormattedMessage += out.str(); - } - else - { - out << std::scientific << value; - mFormattedMessage += out.str(); - } + appendMessage(value); + } + else + { + Type_Integer value = mRuntime[0].mInteger; + mRuntime.pop(); + appendMessage(value); } - break; - default: - break; } } diff --git a/components/misc/messageformatparser.cpp b/components/misc/messageformatparser.cpp index 649d0184d3..67ac07011c 100644 --- a/components/misc/messageformatparser.cpp +++ b/components/misc/messageformatparser.cpp @@ -27,58 +27,71 @@ namespace Misc { for (std::size_t i = 0; i < m.size(); ++i) { - if (m[i] == '%') - { - if (++i < m.size()) - { - if (m[i] == '%') - visitedCharacter('%'); - else - { - char pad = ' '; - if (m[i] == '0' || m[i] == ' ') - { - pad = m[i]; - ++i; - } - - int width = parseNumber(i, m, -1); - - if (i < m.size()) - { - int precision = -1; - if (m[i] == '.') - { - ++i; - precision = parseNumber(i, m, 0); - } - - if (i < m.size()) - { - if (m[i] == 'S' || m[i] == 's') - visitedPlaceholder(StringPlaceholder, pad, width, precision, Notation::Fixed); - else if (m[i] == 'd' || m[i] == 'i') - visitedPlaceholder(IntegerPlaceholder, pad, width, precision, Notation::Fixed); - else if (m[i] == 'f' || m[i] == 'F') - visitedPlaceholder(FloatPlaceholder, pad, width, precision, Notation::Fixed); - else if (m[i] == 'e' || m[i] == 'E') - visitedPlaceholder(FloatPlaceholder, pad, width, precision, Notation::Scientific); - else if (m[i] == 'g' || m[i] == 'G') - visitedPlaceholder(FloatPlaceholder, pad, width, precision, Notation::Shortest); - else if (m[i] == 'a') - visitedPlaceholder(FloatPlaceholder, pad, width, precision, Notation::HexLower); - else if (m[i] == 'A') - visitedPlaceholder(FloatPlaceholder, pad, width, precision, Notation::HexUpper); - else - visitedCharacter(m[i]); - } - } - } - } - } - else + if (m[i] != '%') { visitedCharacter(m[i]); + continue; + } + if (++i == m.size()) + break; + if (m[i] == '%') + { + visitedCharacter('%'); + continue; + } + + int flags = None; + while (i < m.size()) + { + if (m[i] == '-') + flags |= AlignLeft; + else if (m[i] == '+') + flags |= PositiveSign; + else if (m[i] == ' ') + flags |= PositiveSpace; + else if (m[i] == '0') + flags |= PrependZero; + else if (m[i] == '#') + flags |= AlternateForm; + else + break; + ++i; + } + + int width = parseNumber(i, m, -1); + + if (i < m.size()) + { + int precision = -1; + if (m[i] == '.') + { + ++i; + precision = parseNumber(i, m, 0); + } + + if (i < m.size()) + { + if (m[i] == 'S' || m[i] == 's') + visitedPlaceholder(StringPlaceholder, flags, width, precision, Notation::Fixed); + else if (m[i] == 'd' || m[i] == 'i') + visitedPlaceholder(IntegerPlaceholder, flags, width, precision, Notation::Fixed); + else if (m[i] == 'f' || m[i] == 'F') + visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::Fixed); + else if (m[i] == 'e') + visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::ScientificLower); + else if (m[i] == 'E') + visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::ScientificUpper); + else if (m[i] == 'g') + visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::ShortestLower); + else if (m[i] == 'G') + visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::ShortestUpper); + else if (m[i] == 'a') + visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::HexLower); + else if (m[i] == 'A') + visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::HexUpper); + else + visitedCharacter(m[i]); + } } } } diff --git a/components/misc/messageformatparser.hpp b/components/misc/messageformatparser.hpp index eeef29234d..99a42d2739 100644 --- a/components/misc/messageformatparser.hpp +++ b/components/misc/messageformatparser.hpp @@ -15,17 +15,28 @@ namespace Misc FloatPlaceholder }; - enum class Notation + enum Flags { - Fixed, - Scientific, - Shortest, - HexUpper, - HexLower + None = 0, + PositiveSpace = 1, + PositiveSign = 2, + AlignLeft = 4, + PrependZero = 8, + AlternateForm = 16 }; - virtual void visitedPlaceholder( - Placeholder placeholder, char padding, int width, int precision, Notation notation) + enum class Notation : char + { + Fixed = 'f', + ScientificUpper = 'E', + ScientificLower = 'e', + ShortestUpper = 'G', + ShortestLower = 'g', + HexUpper = 'A', + HexLower = 'a' + }; + + virtual void visitedPlaceholder(Placeholder placeholder, int flags, int width, int precision, Notation notation) = 0; virtual void visitedCharacter(char c) = 0;