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(
Placeholder placeholder, char /*padding*/, int /*width*/, int /*precision*/, Notation /*notation*/)
Placeholder placeholder, int /*flags*/, int /*width*/, int /*precision*/, Notation /*notation*/)
{
switch (placeholder)
{

View File

@ -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:

View File

@ -2,8 +2,7 @@
#define INTERPRETER_MISCOPCODES_H_INCLUDED
#include <algorithm>
#include <sstream>
#include <stdexcept>
#include <format>
#include <string>
#include <vector>
@ -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<std::size_t>(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<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();
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;
}
}

View File

@ -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]);
}
}
}
}

View File

@ -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;