#ifndef INTERPRETER_MISCOPCODES_H_INCLUDED #define INTERPRETER_MISCOPCODES_H_INCLUDED #include #include #include #include #include "defines.hpp" #include "opcodes.hpp" #include "runtime.hpp" #include namespace Interpreter { class RuntimeMessageFormatter : public Misc::MessageFormatParser { private: std::string mFormattedMessage; Runtime& mRuntime; protected: void visitedPlaceholder( Placeholder placeholder, int flags, int width, int precision, Notation notation) override { std::string formatString; if (placeholder == StringPlaceholder) { int index = mRuntime[0].mInteger; mRuntime.pop(); std::string_view value = mRuntime.getStringLiteral(index); if (precision >= 0) value = value.substr(0, static_cast(precision)); if (width < 0) mFormattedMessage += value; else { formatString = "{:"; if (flags & PrependZero) formatString += '0'; if (flags & AlignLeft) formatString += '<'; else formatString += '>'; formatString += "{}}"; std::vformat_to( std::back_inserter(mFormattedMessage), formatString, std::make_format_args(value, width)); } } 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) std::vformat_to(std::back_inserter(mFormattedMessage), formatString, std::make_format_args(value, width, precision)); else if (width >= 0) std::vformat_to( std::back_inserter(mFormattedMessage), formatString, std::make_format_args(value, width)); else if (precision >= 0) std::vformat_to(std::back_inserter(mFormattedMessage), formatString, std::make_format_args(value, precision)); else std::vformat_to( std::back_inserter(mFormattedMessage), 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); } } } void visitedCharacter(char c) override { mFormattedMessage += c; } public: RuntimeMessageFormatter(Runtime& runtime) : mRuntime(runtime) { } void process(std::string_view message) override { mFormattedMessage.clear(); MessageFormatParser::process(message); } std::string getFormattedMessage() const { return mFormattedMessage; } }; inline std::string formatMessage(std::string_view message, Runtime& runtime) { RuntimeMessageFormatter formatter(runtime); formatter.process(message); std::string formattedMessage = formatter.getFormattedMessage(); formattedMessage = fixDefinesMsgBox(formattedMessage, runtime.getContext()); return formattedMessage; } class OpMessageBox : public Opcode1 { public: void execute(Runtime& runtime, unsigned int arg0) override { // message int index = runtime[0].mInteger; runtime.pop(); std::string_view message = runtime.getStringLiteral(index); // buttons std::vector buttons; for (std::size_t i = 0; i < arg0; ++i) { index = runtime[0].mInteger; runtime.pop(); buttons.emplace_back(runtime.getStringLiteral(index)); } std::reverse(buttons.begin(), buttons.end()); // handle additional parameters std::string formattedMessage = formatMessage(message, runtime); runtime.getContext().messageBox(formattedMessage, buttons); } }; class OpReport : public Opcode0 { public: void execute(Runtime& runtime) override { // message int index = runtime[0].mInteger; runtime.pop(); std::string_view message = runtime.getStringLiteral(index); // handle additional parameters std::string formattedMessage = formatMessage(message, runtime); runtime.getContext().report(formattedMessage); } }; } #endif