diff options
Diffstat (limited to 'src/openvic/dataloader/NodeTools.cpp')
-rw-r--r-- | src/openvic/dataloader/NodeTools.cpp | 373 |
1 files changed, 207 insertions, 166 deletions
diff --git a/src/openvic/dataloader/NodeTools.cpp b/src/openvic/dataloader/NodeTools.cpp index 6ab2ba6..6e5f7d0 100644 --- a/src/openvic/dataloader/NodeTools.cpp +++ b/src/openvic/dataloader/NodeTools.cpp @@ -3,214 +3,255 @@ #include <charconv> using namespace OpenVic; +using namespace OpenVic::NodeTools; template<typename T> -return_t NodeTools::expect_type(ast::NodeCPtr node, std::function<return_t(T const&)> callback) { - if (node != nullptr) { - if (node->is_type<T>()) { - return callback(ast::cast_node_cptr<T>(node)); +static node_callback_t _expect_type(std::function<return_t(T const&)> callback) { + return [callback](ast::NodeCPtr node) -> return_t { + if (node != nullptr) { + T const* cast_node = node->cast_to<T>(); + if (cast_node != nullptr) { + return callback(*cast_node); + } + Logger::error("Invalid node type ", node->get_type(), " when expecting ", T::get_type_static()); + } else { + Logger::error("Null node when expecting ", T::get_type_static()); } - Logger::error("Invalid node type ", node->get_type(), " when expecting ", T::get_type_static()); - } else { - Logger::error("Null node when expecting ", T::get_type_static()); - } - return FAILURE; + return FAILURE; + }; } -static return_t identifier_callback_wrapper(std::function<return_t(std::string_view)> callback, std::string_view identifier) { - if (!identifier.empty()) { - return callback(identifier); - } - Logger::error("Empty identifier node string"); - return FAILURE; +template<typename T = ast::AbstractStringNode> +requires(std::derived_from<T, ast::AbstractStringNode>) +static std::function<return_t(T const&)> abstract_string_node_callback(std::function<return_t(std::string_view)> callback) { + return [callback](T const& node) -> return_t { + return callback(node._name); + }; } -return_t NodeTools::expect_identifier(ast::NodeCPtr node, std::function<return_t(std::string_view)> callback) { - return expect_type<ast::IdentifierNode>(node, [callback](ast::IdentifierNode const& identifier_node) -> return_t { - return identifier_callback_wrapper(callback, identifier_node._name); - }); +node_callback_t NodeTools::expect_identifier(std::function<return_t(std::string_view)> callback) { + return _expect_type<ast::IdentifierNode>(abstract_string_node_callback<ast::IdentifierNode>(callback)); } -return_t NodeTools::expect_string(ast::NodeCPtr node, std::function<return_t(std::string_view)> callback) { - return expect_type<ast::StringNode>(node, [callback](ast::StringNode const& string_node) -> return_t { - return callback(string_node._name); - }); +node_callback_t NodeTools::expect_string(std::function<return_t(std::string_view)> callback) { + return _expect_type<ast::StringNode>(abstract_string_node_callback<ast::StringNode>(callback)); } -return_t NodeTools::expect_identifier_or_string(ast::NodeCPtr node, std::function<return_t(std::string_view)> callback) { - if (node != nullptr) { - if (node->is_type<ast::IdentifierNode>()) { - return identifier_callback_wrapper(callback, ast::cast_node_cptr<ast::IdentifierNode>(node)._name); - } else if (node->is_type<ast::StringNode>()) { - return callback(ast::cast_node_cptr<ast::StringNode>(node)._name); - } else { +node_callback_t NodeTools::expect_identifier_or_string(std::function<return_t(std::string_view)> callback) { + return [callback](ast::NodeCPtr node) -> return_t { + if (node != nullptr) { + ast::AbstractStringNode const* cast_node = node->cast_to<ast::IdentifierNode>(); + if (cast_node == nullptr) { + cast_node = node->cast_to<ast::StringNode>(); + } + if (cast_node != nullptr) { + return abstract_string_node_callback(callback)(*cast_node); + } Logger::error("Invalid node type ", node->get_type(), " when expecting ", ast::IdentifierNode::get_type_static(), " or ", ast::StringNode::get_type_static()); + } else { + Logger::error("Null node when expecting ", ast::IdentifierNode::get_type_static(), " or ", ast::StringNode::get_type_static()); } - } else { - Logger::error("Null node when expecting ", ast::IdentifierNode::get_type_static(), " or ", ast::StringNode::get_type_static()); - } - return FAILURE; -} - -return_t NodeTools::expect_bool(ast::NodeCPtr node, std::function<return_t(bool)> callback) { - return expect_identifier(node, [callback](std::string_view identifier) -> return_t { - if (identifier == "yes") { - return callback(true); - } else if (identifier == "no") { - return callback(false); - } - Logger::error("Invalid bool identifier text: ", identifier); return FAILURE; - }); + }; } -return_t NodeTools::expect_int(ast::NodeCPtr node, std::function<return_t(int64_t)> callback) { - return expect_identifier(node, [callback](std::string_view identifier) -> return_t { - bool successful = false; - const int64_t val = StringUtils::string_to_int64(identifier, &successful, 10); - if (successful) { - return callback(val); +node_callback_t NodeTools::expect_bool(std::function<return_t(bool)> callback) { + return expect_identifier( + [callback](std::string_view identifier) -> return_t { + if (identifier == "yes") { + return callback(true); + } else if (identifier == "no") { + return callback(false); + } + Logger::error("Invalid bool identifier text: ", identifier); + return FAILURE; } - Logger::error("Invalid int identifier text: ", identifier); - return FAILURE; - }); + ); } -return_t NodeTools::expect_uint(ast::NodeCPtr node, std::function<return_t(uint64_t)> callback) { - return expect_identifier(node, [callback](std::string_view identifier) -> return_t { - bool successful = false; - const uint64_t val = StringUtils::string_to_uint64(identifier, &successful, 10); - if (successful) { - return callback(val); +node_callback_t NodeTools::expect_int(std::function<return_t(int64_t)> callback) { + return expect_identifier( + [callback](std::string_view identifier) -> return_t { + bool successful = false; + const int64_t val = StringUtils::string_to_int64(identifier, &successful, 10); + if (successful) { + return callback(val); + } + Logger::error("Invalid int identifier text: ", identifier); + return FAILURE; } - Logger::error("Invalid uint identifier text: ", identifier); - return FAILURE; - }); + ); } -return_t NodeTools::expect_fixed_point(ast::NodeCPtr node, std::function<return_t(FP)> callback) { - return expect_identifier(node, [callback](std::string_view identifier) -> return_t { - bool successful = false; - const FP val = FP::parse(identifier.data(), identifier.length(), &successful); - if (successful) { - return callback(val); +node_callback_t NodeTools::expect_uint(std::function<return_t(uint64_t)> callback) { + return expect_identifier( + [callback](std::string_view identifier) -> return_t { + bool successful = false; + const uint64_t val = StringUtils::string_to_uint64(identifier, &successful, 10); + if (successful) { + return callback(val); + } + Logger::error("Invalid uint identifier text: ", identifier); + return FAILURE; } - Logger::error("Invalid fixed point identifier text: ", identifier); - return FAILURE; - }); + ); +} + +node_callback_t NodeTools::expect_fixed_point(std::function<return_t(FP)> callback) { + return expect_identifier( + [callback](std::string_view identifier) -> return_t { + bool successful = false; + const FP val = FP::parse(identifier.data(), identifier.length(), &successful); + if (successful) { + return callback(val); + } + Logger::error("Invalid fixed point identifier text: ", identifier); + return FAILURE; + } + ); +} + +node_callback_t NodeTools::expect_colour(std::function<return_t(colour_t)> callback) { + return [callback](ast::NodeCPtr node) -> return_t { + colour_t col = NULL_COLOUR; + uint32_t components = 0; + return_t ret = expect_list_of_length(3, + expect_fixed_point( + [&col, &components](FP val) -> return_t { + return_t ret = SUCCESS; + if (val < 0 || val > 255) { + Logger::error("Invalid colour component: ", val); + val = FP::_0(); + ret = FAILURE; + } + if (val <= 1) val *= 255; + col = (col << 8) | val.to_int32_t(); + components++; + return ret; + } + ) + )(node); + if (components < 3) col <<= 8 * (3 - components); + if (callback(col) != SUCCESS) ret = FAILURE; + return ret; + }; +} + +node_callback_t NodeTools::expect_date(std::function<return_t(Date)> callback) { + return expect_identifier( + [callback](std::string_view identifier) -> return_t { + bool successful = false; + const Date date = Date::from_string(identifier, &successful); + if (successful) { + return callback(date); + } + Logger::error("Invalid date identifier text: ", identifier); + return FAILURE; + } + ); } -return_t NodeTools::expect_colour(ast::NodeCPtr node, std::function<return_t(colour_t)> callback) { - colour_t col = NULL_COLOUR; - uint32_t components = 0; - return_t ret = expect_list_of_length(node, std::bind(expect_fixed_point, std::placeholders::_1, - [&col, &components](FP val) -> return_t { +node_callback_t NodeTools::expect_assign(key_value_callback_t callback) { + return _expect_type<ast::AssignNode>( + [callback](ast::AssignNode const& assign_node) -> return_t { + return callback(assign_node._name, assign_node._initializer.get()); + } + ); +} + +node_callback_t NodeTools::expect_list_and_length(length_callback_t length_callback, node_callback_t callback) { + return _expect_type<ast::AbstractListNode>( + [length_callback, callback](ast::AbstractListNode const& list_node) -> return_t { + std::vector<ast::NodeUPtr> const& list = list_node._statements; return_t ret = SUCCESS; - if (val < 0 || val > 255) { - Logger::error("Invalid colour component: ", val); - val = FP::_0(); + size_t size = length_callback(list.size()); + if (size > list.size()) { + Logger::error("Trying to read more values than the list contains: ", size, " > ", list.size()); + size = list.size(); ret = FAILURE; } - if (val <= 1) val *= 255; - col = (col << 8) | val.to_int32_t(); - components++; + std::for_each(list.begin(), list.begin() + size, + [callback, &ret](ast::NodeUPtr const& sub_node) -> void { + if (callback(sub_node.get()) != SUCCESS) ret = FAILURE; + } + ); return ret; - }), 3); - if (components < 3) col <<= 8 * (3 - components); - if (callback(col) != SUCCESS) ret = FAILURE; - return ret; -} - -return_t NodeTools::expect_date(ast::NodeCPtr node, std::function<return_t(Date)> callback) { - return expect_identifier(node, [callback](std::string_view identifier) -> return_t { - bool successful = false; - const Date date = Date::from_string(identifier, &successful); - if (successful) { - return callback(date); } - Logger::error("Invalid date identifier text: ", identifier); - return FAILURE; - }); + ); } -return_t NodeTools::expect_assign(ast::NodeCPtr node, std::function<return_t(std::string_view, ast::NodeCPtr)> callback) { - return expect_type<ast::AssignNode>(node, [callback](ast::AssignNode const& assign_node) -> return_t { - return callback(assign_node._name, assign_node._initializer.get()); - }); -} - -return_t NodeTools::expect_list_and_length(ast::NodeCPtr node, std::function<size_t(size_t)> length_callback, std::function<return_t(ast::NodeCPtr)> callback, bool file_node) { - const std::function<return_t(std::vector<ast::NodeUPtr> const&)> list_func = [length_callback, callback](std::vector<ast::NodeUPtr> const& list) -> return_t { +node_callback_t NodeTools::expect_list_of_length(size_t length, node_callback_t callback) { + return [length, callback](ast::NodeCPtr node) -> return_t { return_t ret = SUCCESS; - size_t size = length_callback(list.size()); - if (size > list.size()) { - Logger::error("Trying to read more values than the list contains: ", size, " > ", list.size()); - size = list.size(); - ret = FAILURE; - } - std::for_each(list.begin(), list.begin() + size, [callback, &ret](ast::NodeUPtr const& sub_node) -> void { - if (callback(sub_node.get()) != SUCCESS) ret = FAILURE; - }); + if (expect_list_and_length( + [length, &ret](size_t size) -> size_t { + if (size != length) { + Logger::error("List length ", size, " does not match expected length ", length); + ret = FAILURE; + if (length < size) return length; + } + return size; + }, + callback + )(node) != SUCCESS) ret = FAILURE; return ret; }; - if (!file_node) { - return expect_type<ast::ListNode>(node, [list_func](ast::ListNode const& list_node) -> return_t { - return list_func(list_node._statements); - }); - } else { - return expect_type<ast::FileNode>(node, [list_func](ast::FileNode const& file_node) -> return_t { - return list_func(file_node._statements); - }); - } -} - -return_t NodeTools::expect_list_of_length(ast::NodeCPtr node, std::function<return_t(ast::NodeCPtr)> callback, size_t length, bool file_node) { - return_t ret = SUCCESS; - if (expect_list_and_length(node, [length, &ret](size_t size) -> size_t { - if (size != length) { - Logger::error("List length ", size, " does not match expected length ", length); - ret = FAILURE; - if (length < size) return length; - } - return size; - }, callback, file_node) != SUCCESS) ret = FAILURE; - return ret; } -return_t NodeTools::expect_list(ast::NodeCPtr node, std::function<return_t(ast::NodeCPtr)> callback, bool file_node) { - return expect_list_and_length(node, default_length_callback, callback, file_node); +node_callback_t NodeTools::expect_list(node_callback_t callback) { + return expect_list_and_length(default_length_callback, callback); } -return_t NodeTools::expect_dictionary_and_length(ast::NodeCPtr node, std::function<size_t(size_t)> length_callback, std::function<return_t(std::string_view, ast::NodeCPtr)> callback, bool file_node) { - return expect_list_and_length(node, length_callback, std::bind(expect_assign, std::placeholders::_1, callback), file_node); +node_callback_t NodeTools::expect_dictionary_and_length(length_callback_t length_callback, key_value_callback_t callback) { + return expect_list_and_length(length_callback, expect_assign(callback)); } -return_t NodeTools::expect_dictionary(ast::NodeCPtr node, std::function<return_t(std::string_view, ast::NodeCPtr)> callback, bool file_node) { - return expect_dictionary_and_length(node, default_length_callback, callback, file_node); +node_callback_t NodeTools::expect_dictionary(key_value_callback_t callback) { + return expect_dictionary_and_length(default_length_callback, callback); } -return_t NodeTools::expect_dictionary_keys(ast::NodeCPtr node, dictionary_key_map_t const& keys, bool allow_other_keys, bool file_node) { - std::map<std::string, size_t, std::less<void>> key_count; - return_t ret = expect_dictionary(node, [keys, allow_other_keys, &key_count](std::string_view key, ast::NodeCPtr value) -> return_t { - const dictionary_key_map_t::const_iterator it = keys.find(key); - if (it == keys.end()) { - if (allow_other_keys) return SUCCESS; - Logger::error("Invalid dictionary key: ", key); - return FAILURE; - } - const size_t count = ++key_count[it->first]; - dictionary_entry_t const& entry = it->second; - if (!entry.can_repeat && count > 1) { - Logger::error("Invalid repeat of dictionary key: ", key); - return FAILURE; - } - return entry.callback(value); - }, file_node); - for (dictionary_key_map_t::value_type const& entry : keys) { - if (entry.second.must_appear && key_count.find(entry.first) == key_count.end()) { - Logger::error("Mandatory dictionary key not present: ", entry.first); - ret = FAILURE; +node_callback_t NodeTools::_expect_dictionary_keys_and_length(length_callback_t length_callback, bool allow_other_keys, key_map_t&& key_map) { + return [length_callback, allow_other_keys, key_map = std::move(key_map)](ast::NodeCPtr node) mutable -> return_t { + return_t ret = expect_dictionary_and_length( + length_callback, + [&key_map, allow_other_keys](std::string_view key, ast::NodeCPtr value) -> return_t { + const key_map_t::iterator it = key_map.find(key); + if (it == key_map.end()) { + if (allow_other_keys) return SUCCESS; + Logger::error("Invalid dictionary key: ", key); + return FAILURE; + } + dictionary_entry_t& entry = it->second; + if (++entry.count > 1 && !entry.can_repeat()) { + Logger::error("Invalid repeat of dictionary key: ", key); + return FAILURE; + } + return entry.callback(value); + } + )(node); + for (key_map_t::value_type const& key_entry : key_map) { + dictionary_entry_t const& entry = key_entry.second; + if (entry.must_appear() && entry.count < 1) { + Logger::error("Mandatory dictionary key not present: ", key_entry.first); + ret = FAILURE; + } } - } - return ret; + return ret; + }; +} + +node_callback_t NodeTools::name_list_callback(std::vector<std::string>& list) { + return expect_list_reserve_length( + list, + expect_identifier_or_string( + [&list](std::string_view str) -> return_t { + if (!str.empty()) { + list.push_back(std::string { str }); + return SUCCESS; + } + Logger::error("Empty identifier or string"); + return FAILURE; + } + ) + ); } |