Bring messagebox format parsing more in line with printf/vanilla

This commit is contained in:
Evil Eye 2025-08-23 17:26:18 +02:00
parent 14d9be7885
commit 06ef34cbdf
5 changed files with 148 additions and 124 deletions

View File

@ -481,7 +481,7 @@ namespace Compiler
} }
void GetArgumentsFromMessageFormat::visitedPlaceholder( 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) switch (placeholder)
{ {

View File

@ -88,7 +88,7 @@ namespace Compiler
protected: protected:
void visitedPlaceholder( 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 {} void visitedCharacter(char c) override {}
public: public:

View File

@ -2,8 +2,7 @@
#define INTERPRETER_MISCOPCODES_H_INCLUDED #define INTERPRETER_MISCOPCODES_H_INCLUDED
#include <algorithm> #include <algorithm>
#include <sstream> #include <format>
#include <stdexcept>
#include <string> #include <string>
#include <vector> #include <vector>
@ -23,78 +22,79 @@ namespace Interpreter
protected: protected:
void visitedPlaceholder( 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; std::string formatString;
out.fill(padding);
if (width != -1)
out.width(width);
if (precision != -1)
out.precision(precision);
switch (placeholder) if (placeholder == StringPlaceholder)
{
case StringPlaceholder:
{ {
int index = mRuntime[0].mInteger; int index = mRuntime[0].mInteger;
mRuntime.pop(); mRuntime.pop();
out << mRuntime.getStringLiteral(index); std::string_view value = mRuntime.getStringLiteral(index);
mFormattedMessage += out.str(); if (precision >= 0)
value = value.substr(0, static_cast<std::size_t>(precision));
if (width < 0)
mFormattedMessage += value;
else
{
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 IntegerPlaceholder:
{
Type_Integer value = mRuntime[0].mInteger;
mRuntime.pop();
out << value;
mFormattedMessage += out.str();
}
break;
case 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 else
{ {
out << std::scientific << value; formatString = "{:";
mFormattedMessage += out.str(); 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<char>(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();
appendMessage(value);
}
else
{
Type_Integer value = mRuntime[0].mInteger;
mRuntime.pop();
appendMessage(value);
} }
break;
default:
break;
} }
} }

View File

@ -27,18 +27,34 @@ namespace Misc
{ {
for (std::size_t i = 0; i < m.size(); ++i) for (std::size_t i = 0; i < m.size(); ++i)
{ {
if (m[i] != '%')
{
visitedCharacter(m[i]);
continue;
}
if (++i == m.size())
break;
if (m[i] == '%') if (m[i] == '%')
{ {
if (++i < m.size())
{
if (m[i] == '%')
visitedCharacter('%'); 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 else
{ break;
char pad = ' ';
if (m[i] == '0' || m[i] == ' ')
{
pad = m[i];
++i; ++i;
} }
@ -56,19 +72,23 @@ namespace Misc
if (i < m.size()) if (i < m.size())
{ {
if (m[i] == 'S' || m[i] == 's') if (m[i] == 'S' || m[i] == 's')
visitedPlaceholder(StringPlaceholder, pad, width, precision, Notation::Fixed); visitedPlaceholder(StringPlaceholder, flags, width, precision, Notation::Fixed);
else if (m[i] == 'd' || m[i] == 'i') else if (m[i] == 'd' || m[i] == 'i')
visitedPlaceholder(IntegerPlaceholder, pad, width, precision, Notation::Fixed); visitedPlaceholder(IntegerPlaceholder, flags, width, precision, Notation::Fixed);
else if (m[i] == 'f' || m[i] == 'F') else if (m[i] == 'f' || m[i] == 'F')
visitedPlaceholder(FloatPlaceholder, pad, width, precision, Notation::Fixed); visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::Fixed);
else if (m[i] == 'e' || m[i] == 'E') else if (m[i] == 'e')
visitedPlaceholder(FloatPlaceholder, pad, width, precision, Notation::Scientific); visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::ScientificLower);
else if (m[i] == 'g' || m[i] == 'G') else if (m[i] == 'E')
visitedPlaceholder(FloatPlaceholder, pad, width, precision, Notation::Shortest); 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') else if (m[i] == 'a')
visitedPlaceholder(FloatPlaceholder, pad, width, precision, Notation::HexLower); visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::HexLower);
else if (m[i] == 'A') else if (m[i] == 'A')
visitedPlaceholder(FloatPlaceholder, pad, width, precision, Notation::HexUpper); visitedPlaceholder(FloatPlaceholder, flags, width, precision, Notation::HexUpper);
else else
visitedCharacter(m[i]); visitedCharacter(m[i]);
} }
@ -76,10 +96,3 @@ namespace Misc
} }
} }
} }
else
{
visitedCharacter(m[i]);
}
}
}
}

View File

@ -15,17 +15,28 @@ namespace Misc
FloatPlaceholder FloatPlaceholder
}; };
enum class Notation enum Flags
{ {
Fixed, None = 0,
Scientific, PositiveSpace = 1,
Shortest, PositiveSign = 2,
HexUpper, AlignLeft = 4,
HexLower PrependZero = 8,
AlternateForm = 16
}; };
virtual void visitedPlaceholder( enum class Notation : char
Placeholder placeholder, char padding, int width, int precision, Notation notation) {
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; = 0;
virtual void visitedCharacter(char c) = 0; virtual void visitedCharacter(char c) = 0;