From 4520ee465d3d9cf9c5d2da58d79340f58abd0555 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 16 Mar 2024 16:26:26 +0400 Subject: [PATCH 1/6] Do not copy vector --- components/lua/yamlloader.cpp | 2 +- components/lua/yamlloader.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/lua/yamlloader.cpp b/components/lua/yamlloader.cpp index 14553cfac4..41b8fb346f 100644 --- a/components/lua/yamlloader.cpp +++ b/components/lua/yamlloader.cpp @@ -25,7 +25,7 @@ namespace LuaUtil return load(rootNodes, lua); } - sol::object YamlLoader::load(const std::vector rootNodes, const sol::state_view& lua) + sol::object YamlLoader::load(const std::vector& rootNodes, const sol::state_view& lua) { if (rootNodes.empty()) return sol::nil; diff --git a/components/lua/yamlloader.hpp b/components/lua/yamlloader.hpp index 1ca95223cd..2ad9315149 100644 --- a/components/lua/yamlloader.hpp +++ b/components/lua/yamlloader.hpp @@ -30,7 +30,7 @@ namespace LuaUtil String }; - static sol::object load(const std::vector rootNodes, const sol::state_view& lua); + static sol::object load(const std::vector& rootNodes, const sol::state_view& lua); static sol::object getNode(const YAML::Node& node, const sol::state_view& lua, uint64_t depth); From 8037ad7f001582655cc5136ce3c1148e6bfffc55 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 16 Mar 2024 16:59:48 +0400 Subject: [PATCH 2/6] Remove unused includes --- apps/openmw_test_suite/lua/test_yaml.cpp | 1 - components/lua/yamlloader.hpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/apps/openmw_test_suite/lua/test_yaml.cpp b/apps/openmw_test_suite/lua/test_yaml.cpp index c7d484cf51..198cf1d0b5 100644 --- a/apps/openmw_test_suite/lua/test_yaml.cpp +++ b/apps/openmw_test_suite/lua/test_yaml.cpp @@ -1,4 +1,3 @@ -#include "gmock/gmock.h" #include #include diff --git a/components/lua/yamlloader.hpp b/components/lua/yamlloader.hpp index 2ad9315149..0ba2e5a1f1 100644 --- a/components/lua/yamlloader.hpp +++ b/components/lua/yamlloader.hpp @@ -1,9 +1,7 @@ #ifndef COMPONENTS_LUA_YAMLLOADER_H #define COMPONENTS_LUA_YAMLLOADER_H -#include #include -#include #include namespace LuaUtil From b657cb2e4ca138848657408e743f0a7e42b1784e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 16 Mar 2024 17:22:07 +0400 Subject: [PATCH 3/6] Simplify code --- apps/openmw/mwlua/markupbindings.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwlua/markupbindings.cpp b/apps/openmw/mwlua/markupbindings.cpp index 997674b45d..dacdb7ee2c 100644 --- a/apps/openmw/mwlua/markupbindings.cpp +++ b/apps/openmw/mwlua/markupbindings.cpp @@ -19,8 +19,7 @@ namespace MWLua auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); api["loadYaml"] = [lua = context.mLua, vfs](std::string_view fileName) { - auto normalizedName = VFS::Path::normalizeFilename(fileName); - auto file = vfs->getNormalized(normalizedName); + Files::IStreamPtr file = vfs->get(VFS::Path::Normalized(fileName)); return LuaUtil::YamlLoader::load(*file, lua->sol()); }; api["decodeYaml"] = [lua = context.mLua](std::string_view inputData) { From 2523afe9c2d5adf066dafba9395322986002217e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 16 Mar 2024 17:22:25 +0400 Subject: [PATCH 4/6] Use namespace instead of static class --- apps/openmw_test_suite/lua/test_yaml.cpp | 2 + components/lua/yamlloader.cpp | 414 ++++++++++++----------- components/lua/yamlloader.hpp | 38 +-- 3 files changed, 227 insertions(+), 227 deletions(-) diff --git a/apps/openmw_test_suite/lua/test_yaml.cpp b/apps/openmw_test_suite/lua/test_yaml.cpp index 198cf1d0b5..759834c5e1 100644 --- a/apps/openmw_test_suite/lua/test_yaml.cpp +++ b/apps/openmw_test_suite/lua/test_yaml.cpp @@ -1,5 +1,7 @@ #include +#include + #include #include "../testing_util.hpp" diff --git a/components/lua/yamlloader.cpp b/components/lua/yamlloader.cpp index 41b8fb346f..7e2736aa8e 100644 --- a/components/lua/yamlloader.cpp +++ b/components/lua/yamlloader.cpp @@ -3,239 +3,267 @@ #include #include +#include + #include #include namespace LuaUtil { - namespace + namespace YamlLoader { constexpr uint64_t maxDepth = 250; - } - - sol::object YamlLoader::load(const std::string& input, const sol::state_view& lua) - { - std::vector rootNodes = YAML::LoadAll(input); - return LuaUtil::YamlLoader::load(rootNodes, lua); - } - - sol::object YamlLoader::load(std::istream& input, const sol::state_view& lua) - { - std::vector rootNodes = YAML::LoadAll(input); - return load(rootNodes, lua); - } - sol::object YamlLoader::load(const std::vector& rootNodes, const sol::state_view& lua) - { - if (rootNodes.empty()) - return sol::nil; - - if (rootNodes.size() == 1) - return getNode(rootNodes[0], lua, 0); - - sol::table documentsTable(lua, sol::create); - for (const auto& root : rootNodes) + enum class ScalarType { - documentsTable.add(getNode(root, lua, 1)); - } + Boolean, + Decimal, + Float, + Hexadecimal, + Infinity, + NotNumber, + Null, + Octal, + String + }; - return documentsTable; - } + sol::object load(const std::vector& rootNodes, const sol::state_view& lua); - sol::object YamlLoader::getNode(const YAML::Node& node, const sol::state_view& lua, uint64_t depth) - { - if (depth >= maxDepth) - throw std::runtime_error("Maximum layers depth exceeded, probably caused by a circular reference"); + sol::object getNode(const YAML::Node& node, const sol::state_view& lua, uint64_t depth); - ++depth; + sol::table getMap(const YAML::Node& node, const sol::state_view& lua, uint64_t depth); - if (node.IsMap()) - return getMap(node, lua, depth); - else if (node.IsSequence()) - return getArray(node, lua, depth); - else if (node.IsScalar()) - return getScalar(node, lua); - else if (node.IsNull()) - return sol::nil; + sol::table getArray(const YAML::Node& node, const sol::state_view& lua, uint64_t depth); - nodeError(node, "An unknown YAML node encountered"); - } + ScalarType getScalarType(const YAML::Node& node); - sol::table YamlLoader::getMap(const YAML::Node& node, const sol::state_view& lua, uint64_t depth) - { - sol::table childTable(lua, sol::create); + sol::object getScalar(const YAML::Node& node, const sol::state_view& lua); - for (const auto& pair : node) + [[noreturn]] void nodeError(const YAML::Node& node, const std::string& message); + + sol::object load(const std::string& input, const sol::state_view& lua) { - if (pair.first.IsMap()) - nodeError(pair.first, "Only scalar nodes can be used as keys, encountered map instead"); - if (pair.first.IsSequence()) - nodeError(pair.first, "Only scalar nodes can be used as keys, encountered array instead"); - if (pair.first.IsNull()) - nodeError(pair.first, "Only scalar nodes can be used as keys, encountered null instead"); - - auto key = getNode(pair.first, lua, depth); - if (key.get_type() == sol::type::number && std::isnan(key.as())) - nodeError(pair.first, "Only scalar nodes can be used as keys, encountered nan instead"); - - childTable[key] = getNode(pair.second, lua, depth); + std::vector rootNodes = YAML::LoadAll(input); + return load(rootNodes, lua); } - return childTable; - } - - sol::table YamlLoader::getArray(const YAML::Node& node, const sol::state_view& lua, uint64_t depth) - { - sol::table childTable(lua, sol::create); - - for (const auto& child : node) + sol::object load(const std::vector& rootNodes, const sol::state_view& lua) { - childTable.add(getNode(child, lua, depth)); - } + if (rootNodes.empty()) + return sol::nil; - return childTable; - } + if (rootNodes.size() == 1) + return getNode(rootNodes[0], lua, 0); - YamlLoader::ScalarType YamlLoader::getScalarType(const YAML::Node& node) - { - const auto& tag = node.Tag(); - const auto& value = node.Scalar(); - if (tag == "!") - return ScalarType::String; + sol::table documentsTable(lua, sol::create); + for (const auto& root : rootNodes) + { + documentsTable.add(getNode(root, lua, 1)); + } - // Note that YAML allows to explicitely specify a scalar type via tag (e.g. "!!bool"), but it makes no - // sense in Lua: - // 1. Both integers and floats use the "number" type prior to Lua 5.3 - // 2. Strings can be quoted, which is more readable than "!!str" - // 3. Most of possible conversions are invalid or their result is unclear - // So ignore this feature for now. - if (tag != "?") - nodeError(node, "An invalid tag'" + tag + "' encountered"); - - if (value.empty()) - return ScalarType::Null; - - // Resolve type according to YAML 1.2 Core Schema (see https://yaml.org/spec/1.2.2/#103-core-schema) - static const std::regex boolRegex("true|True|TRUE|false|False|FALSE", std::regex_constants::extended); - if (std::regex_match(node.Scalar(), boolRegex)) - return ScalarType::Boolean; - - static const std::regex decimalRegex("[-+]?[0-9]+", std::regex_constants::extended); - if (std::regex_match(node.Scalar(), decimalRegex)) - return ScalarType::Decimal; - - static const std::regex floatRegex( - "[-+]?([.][0-9]+|[0-9]+([.][0-9]*)?)([eE][-+]?[0-9]+)?", std::regex_constants::extended); - if (std::regex_match(node.Scalar(), floatRegex)) - return ScalarType::Float; - - static const std::regex octalRegex("0o[0-7]+", std::regex_constants::extended); - if (std::regex_match(node.Scalar(), octalRegex)) - return ScalarType::Octal; - - static const std::regex hexdecimalRegex("0x[0-9a-fA-F]+", std::regex_constants::extended); - if (std::regex_match(node.Scalar(), hexdecimalRegex)) - return ScalarType::Hexadecimal; - - static const std::regex infinityRegex("[-+]?([.]inf|[.]Inf|[.]INF)", std::regex_constants::extended); - if (std::regex_match(node.Scalar(), infinityRegex)) - return ScalarType::Infinity; - - static const std::regex nanRegex("[.]nan|[.]NaN|[.]NAN", std::regex_constants::extended); - if (std::regex_match(node.Scalar(), nanRegex)) - return ScalarType::NotNumber; - - static const std::regex nullRegex("null|Null|NULL|~", std::regex_constants::extended); - if (std::regex_match(node.Scalar(), nullRegex)) - return ScalarType::Null; - - return ScalarType::String; - } + return documentsTable; + } - sol::object YamlLoader::getScalar(const YAML::Node& node, const sol::state_view& lua) - { - auto type = getScalarType(node); - const auto& value = node.Scalar(); + sol::object load(std::istream& input, const sol::state_view& lua) + { + std::vector rootNodes = YAML::LoadAll(input); + return load(rootNodes, lua); + } - switch (type) + sol::object getNode(const YAML::Node& node, const sol::state_view& lua, uint64_t depth) { - case ScalarType::Null: + if (depth >= maxDepth) + throw std::runtime_error("Maximum layers depth exceeded, probably caused by a circular reference"); + + ++depth; + + if (node.IsMap()) + return getMap(node, lua, depth); + else if (node.IsSequence()) + return getArray(node, lua, depth); + else if (node.IsScalar()) + return getScalar(node, lua); + else if (node.IsNull()) return sol::nil; - case ScalarType::String: - return sol::make_object(lua, value); - case ScalarType::NotNumber: - return sol::make_object(lua, std::nan("")); - case ScalarType::Infinity: - { - if (!value.empty() && value[0] == '-') - return sol::make_object(lua, -std::numeric_limits::infinity()); - return sol::make_object(lua, std::numeric_limits::infinity()); - } - case ScalarType::Boolean: - { - if (Misc::StringUtils::lowerCase(value) == "true") - return sol::make_object(lua, true); + nodeError(node, "An unknown YAML node encountered"); + } - if (Misc::StringUtils::lowerCase(value) == "false") - return sol::make_object(lua, false); + sol::table getMap(const YAML::Node& node, const sol::state_view& lua, uint64_t depth) + { + sol::table childTable(lua, sol::create); - nodeError(node, "Can not read a boolean value '" + value + "'"); - } - case ScalarType::Decimal: + for (const auto& pair : node) { - int offset = 0; + if (pair.first.IsMap()) + nodeError(pair.first, "Only scalar nodes can be used as keys, encountered map instead"); + if (pair.first.IsSequence()) + nodeError(pair.first, "Only scalar nodes can be used as keys, encountered array instead"); + if (pair.first.IsNull()) + nodeError(pair.first, "Only scalar nodes can be used as keys, encountered null instead"); + + auto key = getNode(pair.first, lua, depth); + if (key.get_type() == sol::type::number && std::isnan(key.as())) + nodeError(pair.first, "Only scalar nodes can be used as keys, encountered nan instead"); + + childTable[key] = getNode(pair.second, lua, depth); + } - // std::from_chars does not support "+" sign - if (!value.empty() && value[0] == '+') - ++offset; + return childTable; + } - int result = 0; - const auto status = std::from_chars(value.data() + offset, value.data() + value.size(), result); - if (status.ec == std::errc()) - return sol::make_object(lua, result); + sol::table getArray(const YAML::Node& node, const sol::state_view& lua, uint64_t depth) + { + sol::table childTable(lua, sol::create); - nodeError(node, "Can not read a decimal value '" + value + "'"); - } - case ScalarType::Float: + for (const auto& child : node) { - // Not all compilers support std::from_chars for floats - double result = 0.0; - bool success = YAML::convert::decode(node, result); - if (success) - return sol::make_object(lua, result); - - nodeError(node, "Can not read a float value '" + value + "'"); + childTable.add(getNode(child, lua, depth)); } - case ScalarType::Hexadecimal: - { - int result = 0; - const auto status = std::from_chars(value.data() + 2, value.data() + value.size(), result, 16); - if (status.ec == std::errc()) - return sol::make_object(lua, result); - nodeError(node, "Can not read a hexadecimal value '" + value + "'"); - } - case ScalarType::Octal: - { - int result = 0; - const auto status = std::from_chars(value.data() + 2, value.data() + value.size(), result, 8); - if (status.ec == std::errc()) - return sol::make_object(lua, result); + return childTable; + } + + ScalarType getScalarType(const YAML::Node& node) + { + const auto& tag = node.Tag(); + const auto& value = node.Scalar(); + if (tag == "!") + return ScalarType::String; + + // Note that YAML allows to explicitely specify a scalar type via tag (e.g. "!!bool"), but it makes no + // sense in Lua: + // 1. Both integers and floats use the "number" type prior to Lua 5.3 + // 2. Strings can be quoted, which is more readable than "!!str" + // 3. Most of possible conversions are invalid or their result is unclear + // So ignore this feature for now. + if (tag != "?") + nodeError(node, "An invalid tag'" + tag + "' encountered"); + + if (value.empty()) + return ScalarType::Null; + + // Resolve type according to YAML 1.2 Core Schema (see https://yaml.org/spec/1.2.2/#103-core-schema) + static const std::regex boolRegex("true|True|TRUE|false|False|FALSE", std::regex_constants::extended); + if (std::regex_match(node.Scalar(), boolRegex)) + return ScalarType::Boolean; + + static const std::regex decimalRegex("[-+]?[0-9]+", std::regex_constants::extended); + if (std::regex_match(node.Scalar(), decimalRegex)) + return ScalarType::Decimal; + + static const std::regex floatRegex( + "[-+]?([.][0-9]+|[0-9]+([.][0-9]*)?)([eE][-+]?[0-9]+)?", std::regex_constants::extended); + if (std::regex_match(node.Scalar(), floatRegex)) + return ScalarType::Float; + + static const std::regex octalRegex("0o[0-7]+", std::regex_constants::extended); + if (std::regex_match(node.Scalar(), octalRegex)) + return ScalarType::Octal; + + static const std::regex hexdecimalRegex("0x[0-9a-fA-F]+", std::regex_constants::extended); + if (std::regex_match(node.Scalar(), hexdecimalRegex)) + return ScalarType::Hexadecimal; + + static const std::regex infinityRegex("[-+]?([.]inf|[.]Inf|[.]INF)", std::regex_constants::extended); + if (std::regex_match(node.Scalar(), infinityRegex)) + return ScalarType::Infinity; + + static const std::regex nanRegex("[.]nan|[.]NaN|[.]NAN", std::regex_constants::extended); + if (std::regex_match(node.Scalar(), nanRegex)) + return ScalarType::NotNumber; + + static const std::regex nullRegex("null|Null|NULL|~", std::regex_constants::extended); + if (std::regex_match(node.Scalar(), nullRegex)) + return ScalarType::Null; - nodeError(node, "Can not read an octal value '" + value + "'"); + return ScalarType::String; + } + + sol::object getScalar(const YAML::Node& node, const sol::state_view& lua) + { + auto type = getScalarType(node); + const auto& value = node.Scalar(); + + switch (type) + { + case ScalarType::Null: + return sol::nil; + case ScalarType::String: + return sol::make_object(lua, value); + case ScalarType::NotNumber: + return sol::make_object(lua, std::nan("")); + case ScalarType::Infinity: + { + if (!value.empty() && value[0] == '-') + return sol::make_object(lua, -std::numeric_limits::infinity()); + + return sol::make_object(lua, std::numeric_limits::infinity()); + } + case ScalarType::Boolean: + { + if (Misc::StringUtils::lowerCase(value) == "true") + return sol::make_object(lua, true); + + if (Misc::StringUtils::lowerCase(value) == "false") + return sol::make_object(lua, false); + + nodeError(node, "Can not read a boolean value '" + value + "'"); + } + case ScalarType::Decimal: + { + int offset = 0; + + // std::from_chars does not support "+" sign + if (!value.empty() && value[0] == '+') + ++offset; + + int result = 0; + const auto status = std::from_chars(value.data() + offset, value.data() + value.size(), result); + if (status.ec == std::errc()) + return sol::make_object(lua, result); + + nodeError(node, "Can not read a decimal value '" + value + "'"); + } + case ScalarType::Float: + { + // Not all compilers support std::from_chars for floats + double result = 0.0; + bool success = YAML::convert::decode(node, result); + if (success) + return sol::make_object(lua, result); + + nodeError(node, "Can not read a float value '" + value + "'"); + } + case ScalarType::Hexadecimal: + { + int result = 0; + const auto status = std::from_chars(value.data() + 2, value.data() + value.size(), result, 16); + if (status.ec == std::errc()) + return sol::make_object(lua, result); + + nodeError(node, "Can not read a hexadecimal value '" + value + "'"); + } + case ScalarType::Octal: + { + int result = 0; + const auto status = std::from_chars(value.data() + 2, value.data() + value.size(), result, 8); + if (status.ec == std::errc()) + return sol::make_object(lua, result); + + nodeError(node, "Can not read an octal value '" + value + "'"); + } + default: + nodeError(node, "An unknown scalar '" + value + "' encountered"); } - default: - nodeError(node, "An unknown scalar '" + value + "' encountered"); } - } - [[noreturn]] void YamlLoader::nodeError(const YAML::Node& node, const std::string& message) - { - const auto& mark = node.Mark(); - std::string error = Misc::StringUtils::format( - " at line=%d column=%d position=%d", mark.line + 1, mark.column + 1, mark.pos + 1); - throw std::runtime_error(message + error); + [[noreturn]] void nodeError(const YAML::Node& node, const std::string& message) + { + const auto& mark = node.Mark(); + std::string error = Misc::StringUtils::format( + " at line=%d column=%d position=%d", mark.line + 1, mark.column + 1, mark.pos + 1); + throw std::runtime_error(message + error); + } } - } diff --git a/components/lua/yamlloader.hpp b/components/lua/yamlloader.hpp index 0ba2e5a1f1..c3339d7eb3 100644 --- a/components/lua/yamlloader.hpp +++ b/components/lua/yamlloader.hpp @@ -2,46 +2,16 @@ #define COMPONENTS_LUA_YAMLLOADER_H #include -#include namespace LuaUtil { - class YamlLoader + namespace YamlLoader { - public: - static sol::object load(const std::string& input, const sol::state_view& lua); + sol::object load(const std::string& input, const sol::state_view& lua); - static sol::object load(std::istream& input, const sol::state_view& lua); - - private: - enum class ScalarType - { - Boolean, - Decimal, - Float, - Hexadecimal, - Infinity, - NotNumber, - Null, - Octal, - String - }; - - static sol::object load(const std::vector& rootNodes, const sol::state_view& lua); - - static sol::object getNode(const YAML::Node& node, const sol::state_view& lua, uint64_t depth); - - static sol::table getMap(const YAML::Node& node, const sol::state_view& lua, uint64_t depth); - - static sol::table getArray(const YAML::Node& node, const sol::state_view& lua, uint64_t depth); - - static ScalarType getScalarType(const YAML::Node& node); - - static sol::object getScalar(const YAML::Node& node, const sol::state_view& lua); - - [[noreturn]] static void nodeError(const YAML::Node& node, const std::string& message); - }; + sol::object load(std::istream& input, const sol::state_view& lua); + } } From cb831a59178a065c3f1bc76cea186ca55fd6e252 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Mar 2024 17:22:10 +0400 Subject: [PATCH 5/6] Add more includes just for sure --- components/lua/yamlloader.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/lua/yamlloader.cpp b/components/lua/yamlloader.cpp index 7e2736aa8e..30323fe116 100644 --- a/components/lua/yamlloader.cpp +++ b/components/lua/yamlloader.cpp @@ -1,7 +1,12 @@ #include "yamlloader.hpp" #include +#include +#include #include +#include +#include +#include #include From 2d3a8ca0fc77f6d1532e9e6086b292b4a1275cf5 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Mar 2024 18:15:23 +0400 Subject: [PATCH 6/6] Do not use an inner namespace --- apps/openmw/mwlua/markupbindings.cpp | 4 +- apps/openmw_test_suite/lua/test_yaml.cpp | 54 ++++++++++++------------ components/lua/yamlloader.cpp | 36 +++++++++------- components/lua/yamlloader.hpp | 14 +++--- 4 files changed, 57 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwlua/markupbindings.cpp b/apps/openmw/mwlua/markupbindings.cpp index dacdb7ee2c..f0b9d67a51 100644 --- a/apps/openmw/mwlua/markupbindings.cpp +++ b/apps/openmw/mwlua/markupbindings.cpp @@ -20,10 +20,10 @@ namespace MWLua api["loadYaml"] = [lua = context.mLua, vfs](std::string_view fileName) { Files::IStreamPtr file = vfs->get(VFS::Path::Normalized(fileName)); - return LuaUtil::YamlLoader::load(*file, lua->sol()); + return LuaUtil::loadYaml(*file, lua->sol()); }; api["decodeYaml"] = [lua = context.mLua](std::string_view inputData) { - return LuaUtil::YamlLoader::load(std::string(inputData), lua->sol()); + return LuaUtil::loadYaml(std::string(inputData), lua->sol()); }; return LuaUtil::makeReadOnly(api); diff --git a/apps/openmw_test_suite/lua/test_yaml.cpp b/apps/openmw_test_suite/lua/test_yaml.cpp index 759834c5e1..fa28889440 100644 --- a/apps/openmw_test_suite/lua/test_yaml.cpp +++ b/apps/openmw_test_suite/lua/test_yaml.cpp @@ -1,17 +1,19 @@ #include +#include +#include +#include + #include #include -#include "../testing_util.hpp" - namespace { template bool checkNumber(sol::state_view& lua, const std::string& inputData, T requiredValue) { - sol::object result = LuaUtil::YamlLoader::load(inputData, lua); + sol::object result = LuaUtil::loadYaml(inputData, lua); if (result.get_type() != sol::type::number) return false; @@ -20,7 +22,7 @@ namespace bool checkBool(sol::state_view& lua, const std::string& inputData, bool requiredValue) { - sol::object result = LuaUtil::YamlLoader::load(inputData, lua); + sol::object result = LuaUtil::loadYaml(inputData, lua); if (result.get_type() != sol::type::boolean) return false; @@ -29,13 +31,13 @@ namespace bool checkNil(sol::state_view& lua, const std::string& inputData) { - sol::object result = LuaUtil::YamlLoader::load(inputData, lua); + sol::object result = LuaUtil::loadYaml(inputData, lua); return result == sol::nil; } bool checkNan(sol::state_view& lua, const std::string& inputData) { - sol::object result = LuaUtil::YamlLoader::load(inputData, lua); + sol::object result = LuaUtil::loadYaml(inputData, lua); if (result.get_type() != sol::type::number) return false; @@ -44,7 +46,7 @@ namespace bool checkString(sol::state_view& lua, const std::string& inputData, const std::string& requiredValue) { - sol::object result = LuaUtil::YamlLoader::load(inputData, lua); + sol::object result = LuaUtil::loadYaml(inputData, lua); if (result.get_type() != sol::type::string) return false; @@ -53,7 +55,7 @@ namespace bool checkString(sol::state_view& lua, const std::string& inputData) { - sol::object result = LuaUtil::YamlLoader::load(inputData, lua); + sol::object result = LuaUtil::loadYaml(inputData, lua); if (result.get_type() != sol::type::string) return false; @@ -165,7 +167,7 @@ namespace try { YAML::Node root = YAML::Load(input); - sol::object result = LuaUtil::YamlLoader::load(input, lua); + sol::object result = LuaUtil::loadYaml(input, lua); } catch (const std::runtime_error& e) { @@ -180,29 +182,29 @@ namespace { sol::state lua; - sol::object map = LuaUtil::YamlLoader::load("{ x: , y: 2, 4: 5 }", lua); + sol::object map = LuaUtil::loadYaml("{ x: , y: 2, 4: 5 }", lua); ASSERT_EQ(map.as()["x"], sol::nil); ASSERT_EQ(map.as()["y"], 2); ASSERT_EQ(map.as()[4], 5); - sol::object array = LuaUtil::YamlLoader::load("[ 3, 4 ]", lua); + sol::object array = LuaUtil::loadYaml("[ 3, 4 ]", lua); ASSERT_EQ(array.as()[1], 3); - sol::object emptyTable = LuaUtil::YamlLoader::load("{}", lua); + sol::object emptyTable = LuaUtil::loadYaml("{}", lua); ASSERT_TRUE(emptyTable.as().empty()); - sol::object emptyArray = LuaUtil::YamlLoader::load("[]", lua); + sol::object emptyArray = LuaUtil::loadYaml("[]", lua); ASSERT_TRUE(emptyArray.as().empty()); - ASSERT_THROW(LuaUtil::YamlLoader::load("{ null: 1 }", lua), std::runtime_error); - ASSERT_THROW(LuaUtil::YamlLoader::load("{ .nan: 1 }", lua), std::runtime_error); + ASSERT_THROW(LuaUtil::loadYaml("{ null: 1 }", lua), std::runtime_error); + ASSERT_THROW(LuaUtil::loadYaml("{ .nan: 1 }", lua), std::runtime_error); const std::string scalarArrayInput = R"( - First Scalar - 1 - true)"; - sol::object scalarArray = LuaUtil::YamlLoader::load(scalarArrayInput, lua); + sol::object scalarArray = LuaUtil::loadYaml(scalarArrayInput, lua); ASSERT_EQ(scalarArray.as()[1], std::string("First Scalar")); ASSERT_EQ(scalarArray.as()[2], 1); ASSERT_EQ(scalarArray.as()[3], true); @@ -213,7 +215,7 @@ namespace float: 0.278 # Float value bool: false # Boolean value)"; - sol::object scalarMapWithComments = LuaUtil::YamlLoader::load(scalarMapWithCommentsInput, lua); + sol::object scalarMapWithComments = LuaUtil::loadYaml(scalarMapWithCommentsInput, lua); ASSERT_EQ(scalarMapWithComments.as()["string"], std::string("str")); ASSERT_EQ(scalarMapWithComments.as()["integer"], 65); ASSERT_EQ(scalarMapWithComments.as()["float"], 0.278); @@ -229,7 +231,7 @@ namespace - false - 1)"; - sol::object mapOfArrays = LuaUtil::YamlLoader::load(mapOfArraysInput, lua); + sol::object mapOfArrays = LuaUtil::loadYaml(mapOfArraysInput, lua); ASSERT_EQ(mapOfArrays.as()["x"][3], true); ASSERT_EQ(mapOfArrays.as()["y"][1], std::string("aaa")); @@ -243,7 +245,7 @@ namespace hr: 63 avg: 0.288)"; - sol::object arrayOfMaps = LuaUtil::YamlLoader::load(arrayOfMapsInput, lua); + sol::object arrayOfMaps = LuaUtil::loadYaml(arrayOfMapsInput, lua); ASSERT_EQ(arrayOfMaps.as()[1]["avg"], 0.278); ASSERT_EQ(arrayOfMaps.as()[2]["name"], std::string("Name2")); @@ -251,7 +253,7 @@ namespace - [Name1, 65, 0.278] - [Name2 , 63, 0.288])"; - sol::object arrayOfArrays = LuaUtil::YamlLoader::load(arrayOfArraysInput, lua); + sol::object arrayOfArrays = LuaUtil::loadYaml(arrayOfArraysInput, lua); ASSERT_EQ(arrayOfArrays.as()[1][2], 65); ASSERT_EQ(arrayOfArrays.as()[2][1], std::string("Name2")); @@ -262,7 +264,7 @@ namespace avg: 0.288, })"; - sol::object mapOfMaps = LuaUtil::YamlLoader::load(mapOfMapsInput, lua); + sol::object mapOfMaps = LuaUtil::loadYaml(mapOfMapsInput, lua); ASSERT_EQ(mapOfMaps.as()["Name1"]["hr"], 65); ASSERT_EQ(mapOfMaps.as()["Name2"]["avg"], 0.288); } @@ -282,7 +284,7 @@ namespace " - 3\n" " - false"; - sol::object twoDocuments = LuaUtil::YamlLoader::load(twoDocumentsInput, lua); + sol::object twoDocuments = LuaUtil::loadYaml(twoDocumentsInput, lua); ASSERT_EQ(twoDocuments.as()[1][1], std::string("First Scalar")); ASSERT_EQ(twoDocuments.as()[2][3], false); @@ -295,7 +297,7 @@ namespace - *a # Subsequent occurrence - Name2)"; - sol::object anchor = LuaUtil::YamlLoader::load(anchorInput, lua); + sol::object anchor = LuaUtil::loadYaml(anchorInput, lua); ASSERT_EQ(anchor.as()["y"][1], std::string("Value1")); const std::string compoundKeyInput = R"( @@ -307,7 +309,7 @@ namespace String4 ] : [ 2, 3, 4 ])"; - ASSERT_THROW(LuaUtil::YamlLoader::load(compoundKeyInput, lua), std::runtime_error); + ASSERT_THROW(LuaUtil::loadYaml(compoundKeyInput, lua), std::runtime_error); const std::string compactNestedMappingInput = R"( - item : Item1 @@ -317,7 +319,7 @@ namespace - item : Item3 quantity: 11)"; - sol::object compactNestedMapping = LuaUtil::YamlLoader::load(compactNestedMappingInput, lua); + sol::object compactNestedMapping = LuaUtil::loadYaml(compactNestedMappingInput, lua); ASSERT_EQ(compactNestedMapping.as()[2]["quantity"], 4); } @@ -347,7 +349,7 @@ namespace quoted: "So does this quoted scalar.\n")"; - sol::object multiLinePlanarScalars = LuaUtil::YamlLoader::load(multiLinePlanarScalarsInput, lua); + sol::object multiLinePlanarScalars = LuaUtil::loadYaml(multiLinePlanarScalarsInput, lua); ASSERT_TRUE( multiLinePlanarScalars.as()["plain"] == std::string("This unquoted scalar spans many lines.")); ASSERT_TRUE(multiLinePlanarScalars.as()["quoted"] == std::string("So does this quoted scalar.\n")); diff --git a/components/lua/yamlloader.cpp b/components/lua/yamlloader.cpp index 30323fe116..df83af6253 100644 --- a/components/lua/yamlloader.cpp +++ b/components/lua/yamlloader.cpp @@ -8,6 +8,9 @@ #include #include +#include +#include + #include #include @@ -15,7 +18,7 @@ namespace LuaUtil { - namespace YamlLoader + namespace { constexpr uint64_t maxDepth = 250; @@ -32,7 +35,7 @@ namespace LuaUtil String }; - sol::object load(const std::vector& rootNodes, const sol::state_view& lua); + sol::object loadAll(const std::vector& rootNodes, const sol::state_view& lua); sol::object getNode(const YAML::Node& node, const sol::state_view& lua, uint64_t depth); @@ -45,14 +48,23 @@ namespace LuaUtil sol::object getScalar(const YAML::Node& node, const sol::state_view& lua); [[noreturn]] void nodeError(const YAML::Node& node, const std::string& message); + } - sol::object load(const std::string& input, const sol::state_view& lua) - { - std::vector rootNodes = YAML::LoadAll(input); - return load(rootNodes, lua); - } + sol::object loadYaml(const std::string& input, const sol::state_view& lua) + { + std::vector rootNodes = YAML::LoadAll(input); + return loadAll(rootNodes, lua); + } - sol::object load(const std::vector& rootNodes, const sol::state_view& lua) + sol::object loadYaml(std::istream& input, const sol::state_view& lua) + { + std::vector rootNodes = YAML::LoadAll(input); + return loadAll(rootNodes, lua); + } + + namespace + { + sol::object loadAll(const std::vector& rootNodes, const sol::state_view& lua) { if (rootNodes.empty()) return sol::nil; @@ -69,12 +81,6 @@ namespace LuaUtil return documentsTable; } - sol::object load(std::istream& input, const sol::state_view& lua) - { - std::vector rootNodes = YAML::LoadAll(input); - return load(rootNodes, lua); - } - sol::object getNode(const YAML::Node& node, const sol::state_view& lua, uint64_t depth) { if (depth >= maxDepth) @@ -143,7 +149,7 @@ namespace LuaUtil // 3. Most of possible conversions are invalid or their result is unclear // So ignore this feature for now. if (tag != "?") - nodeError(node, "An invalid tag'" + tag + "' encountered"); + nodeError(node, "An invalid tag '" + tag + "' encountered"); if (value.empty()) return ScalarType::Null; diff --git a/components/lua/yamlloader.hpp b/components/lua/yamlloader.hpp index c3339d7eb3..6f28da66ce 100644 --- a/components/lua/yamlloader.hpp +++ b/components/lua/yamlloader.hpp @@ -1,18 +1,16 @@ #ifndef COMPONENTS_LUA_YAMLLOADER_H #define COMPONENTS_LUA_YAMLLOADER_H -#include +#include +#include + +#include namespace LuaUtil { + sol::object loadYaml(const std::string& input, const sol::state_view& lua); - namespace YamlLoader - { - sol::object load(const std::string& input, const sol::state_view& lua); - - sol::object load(std::istream& input, const sol::state_view& lua); - } - + sol::object loadYaml(std::istream& input, const sol::state_view& lua); } #endif // COMPONENTS_LUA_YAMLLOADER_H