diff --git a/components/lua/utf8.cpp b/components/lua/utf8.cpp index c8be068353..9b7fc97de8 100644 --- a/components/lua/utf8.cpp +++ b/components/lua/utf8.cpp @@ -1,11 +1,27 @@ +#include + #include "utf8.hpp" -#include "luastate.hpp" namespace { static constexpr std::string_view UTF8PATT = "[%z\x01-\x7F\xC2-\xF4][\x80-\xBF]*"; // %z is deprecated in Lua5.2 static constexpr uint32_t MAXUTF = 0x7FFFFFFFu; static constexpr uint32_t MAXUNICODE = 0x10FFFFu; + + inline static double getInteger(const sol::stack_proxy arg, const size_t& n, const std::string_view& name) + { + double integer; + if (!arg.is()) + throw std::runtime_error(std::format("bad argument #{} to '{}' (number expected, got {})", n, name, + sol::type_name(arg.lua_state(), arg.get_type()))); + + if (std::modf(arg, &integer) != 0) + throw std::runtime_error( + std::format("bad argument #{} to '{}' (number has no integer representation)", n, name)); + + return integer; + } + } namespace LuaUtf8 @@ -16,6 +32,19 @@ namespace LuaUtf8 utf8["charpattern"] = UTF8PATT; + utf8["char"] = [](const sol::variadic_args args) -> std::string { + std::string result{}; + std::wstring_convert> converter; + for (size_t i = 0; i < args.size(); ++i) + { + int64_t codepoint = getInteger(args[i], (i + 1), "char"); + if (codepoint < 0 || codepoint > MAXUTF) + throw std::runtime_error(std::format("bad argument #{} to 'char' (value out of range)", (i + 1))); + + result += converter.to_bytes(codepoint); + } + return result; + }; return utf8; } } diff --git a/components/lua/utf8.hpp b/components/lua/utf8.hpp index cb8666ea33..dd936b3b5e 100644 --- a/components/lua/utf8.hpp +++ b/components/lua/utf8.hpp @@ -1,6 +1,8 @@ #ifndef COMPONENTS_LUA_UTF8_H #define COMPONENTS_LUA_UTF8_H +#include + namespace LuaUtf8 { sol::table initUtf8Package(sol::state_view&);