#pragma once #include #include #include #include #include #include #include #include "openvic-simulation/types/Colour.hpp" #include "openvic-simulation/types/Date.hpp" #include "openvic-simulation/types/HasIdentifier.hpp" #include "openvic-simulation/types/IndexedMap.hpp" #include "openvic-simulation/types/OrderedContainers.hpp" #include "openvic-simulation/types/Vector.hpp" #include "openvic-simulation/utility/Getters.hpp" #include "openvic-simulation/utility/TslHelper.hpp" #define MOV(...) static_cast&&>(__VA_ARGS__) #define FWD(...) static_cast(__VA_ARGS__) namespace OpenVic { namespace ast { using namespace ovdl::v2script::ast; using NodeCPtr = Node const*; constexpr std::string_view get_type_name(NodeKind kind) { #define NODE_CASE(Node) \ case Node: return OpenVic::utility::type_name(); switch (kind) { using enum NodeKind; NODE_CASE(FileTree); NODE_CASE(IdentifierValue); NODE_CASE(StringValue); NODE_CASE(ListValue); NODE_CASE(NullValue); NODE_CASE(EventStatement); NODE_CASE(AssignStatement); NODE_CASE(ValueStatement); default: ovdl::detail::unreachable(); } } #undef NODE_CASE } using name_list_t = std::vector; std::ostream& operator<<(std::ostream& stream, name_list_t const& name_list); template concept Reservable = requires(T& t, size_t size) { { t.size() } -> std::same_as; t.reserve(size); }; constexpr void reserve_more(Reservable auto& t, size_t size) { t.reserve(t.size() + size); } namespace NodeTools { template concept Functor = requires(Fn&& fn, Args&&... args) { { std::invoke(FWD(fn), FWD(args)...) } -> std::same_as; }; template concept FunctorConvertible = requires(Fn&& fn, Args&&... args) { { std::invoke(FWD(fn), FWD(args)...) } -> std::convertible_to; }; template concept Callback = Functor; template concept NodeCallback = Callback; template concept KeyValueCallback = Callback; template concept LengthCallback = Functor; template using callback_t = std::function; using node_callback_t = callback_t; constexpr bool success_callback(ast::NodeCPtr) { return true; } using key_value_callback_t = callback_t; constexpr bool key_value_success_callback(std::string_view, ast::NodeCPtr) { return true; } inline bool key_value_invalid_callback(std::string_view key, ast::NodeCPtr) { Logger::error("Invalid dictionary key: ", key); return false; } node_callback_t expect_identifier(callback_t callback); node_callback_t expect_string(callback_t callback, bool allow_empty = false); node_callback_t expect_identifier_or_string(callback_t callback, bool allow_empty = false); node_callback_t expect_bool(callback_t callback); node_callback_t expect_int_bool(callback_t callback); node_callback_t expect_int64(callback_t callback, int base = 10); node_callback_t expect_uint64(callback_t callback, int base = 10); template NodeCallback auto expect_int(callback_t& callback, int base = 10) { return expect_int64([callback](int64_t val) -> bool { if (static_cast(std::numeric_limits::lowest()) <= val && val <= static_cast(std::numeric_limits::max())) { return callback(val); } Logger::error( "Invalid int: ", val, " (valid range: [", static_cast(std::numeric_limits::lowest()), ", ", static_cast(std::numeric_limits::max()), "])" ); return false; }, base); } template NodeCallback auto expect_int(callback_t&& callback, int base = 10) { return expect_int(callback, base); } template NodeCallback auto expect_uint(callback_t& callback, int base = 10) { return expect_uint64([callback](uint64_t val) -> bool { if (val <= static_cast(std::numeric_limits::max())) { return callback(val); } Logger::error( "Invalid uint: ", val, " (valid range: [0, ", static_cast(std::numeric_limits::max()), "])" ); return false; }, base); } template NodeCallback auto expect_uint(callback_t&& callback, int base = 10) { return expect_uint(callback, base); } callback_t expect_fixed_point_str(callback_t callback); node_callback_t expect_fixed_point(callback_t callback); /* Expect a list of 3 base 10 values, each either in the range [0, 1] or (1, 255], representing RGB components. */ node_callback_t expect_colour(callback_t callback); /* Expect a hexadecimal value representing a colour in ARGB format. */ node_callback_t expect_colour_hex(callback_t callback); callback_t expect_date_str(callback_t callback); node_callback_t expect_date(callback_t callback); node_callback_t expect_date_string(callback_t callback); node_callback_t expect_date_identifier_or_string(callback_t callback); node_callback_t expect_years(callback_t callback); node_callback_t expect_months(callback_t callback); node_callback_t expect_days(callback_t callback); node_callback_t expect_ivec2(callback_t callback); node_callback_t expect_fvec2(callback_t callback); node_callback_t expect_assign(key_value_callback_t callback); using length_callback_t = std::function; constexpr size_t default_length_callback(size_t size) { return size; }; node_callback_t expect_list_and_length(length_callback_t length_callback, node_callback_t callback); node_callback_t expect_list_of_length(size_t length, node_callback_t callback); node_callback_t expect_list(node_callback_t callback); node_callback_t expect_length(callback_t callback); node_callback_t expect_key( ovdl::symbol key, node_callback_t callback, bool* key_found = nullptr, bool allow_duplicates = false ); node_callback_t expect_key( std::string_view key, node_callback_t callback, bool* key_found = nullptr, bool allow_duplicates = false ); node_callback_t expect_dictionary_and_length(length_callback_t length_callback, key_value_callback_t callback); node_callback_t expect_dictionary(key_value_callback_t callback); struct dictionary_entry_t { enum class expected_count_t : uint8_t { _MUST_APPEAR = 0b01, _CAN_REPEAT = 0b10, ZERO_OR_ONE = 0, ONE_EXACTLY = _MUST_APPEAR, ZERO_OR_MORE = _CAN_REPEAT, ONE_OR_MORE = _MUST_APPEAR | _CAN_REPEAT } expected_count; node_callback_t callback; size_t count; dictionary_entry_t(expected_count_t new_expected_count, node_callback_t&& new_callback) : expected_count { new_expected_count }, callback { MOV(new_callback) }, count { 0 } {} constexpr bool must_appear() const { return static_cast(expected_count) & static_cast(expected_count_t::_MUST_APPEAR); } constexpr bool can_repeat() const { return static_cast(expected_count) & static_cast(expected_count_t::_CAN_REPEAT); } }; using enum dictionary_entry_t::expected_count_t; template using template_key_map_t = template_string_map_t; using key_map_t = template_key_map_t; using case_insensitive_key_map_t = template_key_map_t; template bool add_key_map_entry( Map&& key_map, std::string_view key, dictionary_entry_t::expected_count_t expected_count, NodeCallback auto&& callback ) { if (!key_map.contains(key)) { key_map.emplace(key, dictionary_entry_t { expected_count, MOV(callback) }); return true; } Logger::error("Duplicate expected dictionary key: ", key); return false; } template bool remove_key_map_entry(Map&& key_map, std::string_view key) { if (key_map.erase(key) == 0) { Logger::error("Failed to find dictionary key to remove: ", key); return false; } return true; } template KeyValueCallback auto dictionary_keys_callback( Map&& key_map, KeyValueCallback auto&& default_callback ) { return [&key_map, default_callback = FWD(default_callback)](std::string_view key, ast::NodeCPtr value) mutable -> bool { typename std::remove_reference_t::iterator it = key_map.find(key); if (it == key_map.end()) { return default_callback(key, value); } dictionary_entry_t& entry = it.value(); if (++entry.count > 1 && !entry.can_repeat()) { Logger::error("Invalid repeat of dictionary key: ", key); return false; } if (entry.callback(value)) { return true; } else { Logger::error("Callback failed for dictionary key: ", key); return false; } }; } template bool check_key_map_counts(Map&& key_map) { bool ret = true; for (auto key_entry : mutable_iterator(key_map)) { dictionary_entry_t& entry = key_entry.second; if (entry.must_appear() && entry.count < 1) { Logger::error("Mandatory dictionary key not present: ", key_entry.first); ret = false; } entry.count = 0; } return ret; } template constexpr bool add_key_map_entries(Map&& key_map) { return true; } template bool add_key_map_entries( Map&& key_map, std::string_view key, dictionary_entry_t::expected_count_t expected_count, NodeCallback auto&& callback, Args&&... args ) { bool ret = add_key_map_entry(FWD(key_map), FWD(key), expected_count, FWD(callback)); ret &= add_key_map_entries(FWD(key_map), FWD(args)...); return ret; } template NodeCallback auto expect_dictionary_key_map_and_length_and_default( Map&& key_map, LengthCallback auto&& length_callback, KeyValueCallback auto&& default_callback ) { return [length_callback = FWD(length_callback), default_callback = FWD(default_callback), key_map = MOV(key_map)](ast::NodeCPtr node) mutable -> bool { bool ret = expect_dictionary_and_length( FWD(length_callback), dictionary_keys_callback(key_map, FWD(default_callback)) )(node); ret &= check_key_map_counts(key_map); return ret; }; } template NodeCallback auto expect_dictionary_key_map_and_length( Map&& key_map, LengthCallback auto&& length_callback ) { return expect_dictionary_key_map_and_length_and_default( FWD(key_map), FWD(length_callback), key_value_invalid_callback ); } template NodeCallback auto expect_dictionary_key_map_and_default( Map&& key_map, KeyValueCallback auto&& default_callback ) { return expect_dictionary_key_map_and_length_and_default( FWD(key_map), default_length_callback, FWD(default_callback) ); } template NodeCallback auto expect_dictionary_key_map(template_key_map_t&& key_map) { return expect_dictionary_key_map_and_length_and_default( MOV(key_map), default_length_callback, key_value_invalid_callback ); } template NodeCallback auto expect_dictionary_key_map_and_length_and_default( Map&& key_map, LengthCallback auto&& length_callback, KeyValueCallback auto&& default_callback, Args&&... args ) { // TODO - pass return value back up (part of big key_map_t rewrite?) add_key_map_entries(FWD(key_map), FWD(args)...); return expect_dictionary_key_map_and_length_and_default(FWD(key_map), FWD(length_callback), FWD(default_callback)); } template NodeCallback auto expect_dictionary_keys_and_length_and_default( LengthCallback auto&& length_callback, KeyValueCallback auto&& default_callback, Args&&... args ) { return expect_dictionary_key_map_and_length_and_default( template_key_map_t {}, FWD(length_callback), FWD(default_callback), FWD(args)... ); } template NodeCallback auto expect_dictionary_keys_and_length(LengthCallback auto&& length_callback, Args&&... args) { return expect_dictionary_key_map_and_length_and_default( template_key_map_t {}, FWD(length_callback), key_value_invalid_callback, FWD(args)... ); } template NodeCallback auto expect_dictionary_keys_and_default(KeyValueCallback auto&& default_callback, Args&&... args) { return expect_dictionary_key_map_and_length_and_default( template_key_map_t {}, default_length_callback, FWD(default_callback), FWD(args)... ); } template NodeCallback auto expect_dictionary_keys(Args&&... args) { return expect_dictionary_key_map_and_length_and_default( template_key_map_t {}, default_length_callback, key_value_invalid_callback, FWD(args)... ); } LengthCallback auto reserve_length_callback(Reservable auto& reservable) { return [&reservable](size_t size) -> size_t { reserve_more(reservable, size); return size; }; } NodeCallback auto expect_list_reserve_length(Reservable auto& reservable, NodeCallback auto&& callback) { return expect_list_and_length(reserve_length_callback(reservable), FWD(callback)); } NodeCallback auto expect_dictionary_reserve_length(Reservable auto& reservable, KeyValueCallback auto&& callback) { return expect_dictionary_and_length(reserve_length_callback(reservable), FWD(callback)); } template NodeCallback auto expect_dictionary_key_map_reserve_length_and_default( Reservable auto& reservable, Map&& key_map, KeyValueCallback auto&& default_callback, Args&&... args ) { return expect_dictionary_key_map_and_length_and_default( FWD(key_map), reserve_length_callback(reservable), FWD(default_callback), FWD(args)... ); } template NodeCallback auto expect_dictionary_key_map_reserve_length( Reservable auto& reservable, Map&& key_map, Args&&... args ) { return expect_dictionary_key_map_and_length(FWD(key_map), reserve_length_callback(reservable), FWD(args)...); } template NodeCallback auto expect_dictionary_keys_reserve_length_and_default( Reservable auto& reservable, KeyValueCallback auto&& default_callback, Args&&... args ) { return expect_dictionary_keys_and_length_and_default( reserve_length_callback(reservable), FWD(default_callback), FWD(args)... ); } template NodeCallback auto expect_dictionary_keys_reserve_length(Reservable auto& reservable, Args&&... args) { return expect_dictionary_keys_and_length(reserve_length_callback(reservable), FWD(args)...); } node_callback_t name_list_callback(callback_t callback); template Callback auto expect_mapped_string( template_string_map_t const& map, Callback auto&& callback, bool warn = false ) { return [&map, callback = FWD(callback), warn](std::string_view string) -> bool { const typename template_string_map_t::const_iterator it = map.find(string); if (it != map.end()) { return callback(it->second); } Logger::warn_or_error(warn, "String not found in map: ", string); return warn; }; } template Callback auto assign_variable_callback_cast(auto& var) { return [&var](T val) -> bool { var = val; return true; }; } template requires std::is_integral_v || std::is_enum_v callback_t assign_variable_callback_cast(auto& var) { return [&var](T val) -> bool { var = val; return true; }; } template Callback auto assign_variable_callback(T& var) { return assign_variable_callback_cast(var); } callback_t assign_variable_callback_string(std::string& var); template Callback auto move_variable_callback(T& var) { return [&var](T&& val) -> bool { var = std::move(val); return true; }; } template requires requires(T& t) { t += T {}; } Callback auto add_variable_callback(T& var) { return [&var](T val) -> bool { var += val; return true; }; } template requires requires(T& t) { t++; } KeyValueCallback auto increment_callback(T& var) { return [&var](std::string_view, ast::NodeCPtr) -> bool { var++; return true; }; } template Callback auto assign_variable_callback_pointer(T const*& var) { return [&var](T const& val) -> bool { var = &val; return true; }; } /* By default this will only allow an optional to be set once. Set allow_overwrite * to true to allow multiple assignments, with the last taking precedence. */ template Callback auto assign_variable_callback_pointer_opt( std::optional& var, bool allow_overwrite = false ) { return [&var, allow_overwrite](T const& val) -> bool { if (!allow_overwrite && var.has_value()) { Logger::error("Canoot assign pointer value to already-initialised optional!"); return false; } var = &val; return true; }; } template Callback auto vector_callback(std::vector& vec) { return [&vec](T val) -> bool { vec.emplace_back(std::move(val)); return true; }; } template Callback auto vector_callback(std::vector& vec) { return vector_callback(vec); } template Callback auto vector_callback_pointer(std::vector& vec) { return [&vec](T& val) -> bool { vec.emplace_back(&val); return true; }; } template Callback auto set_callback(tsl::ordered_set& set, bool warn = false) { return [&set, warn](T val) -> bool { if (set.emplace(std::move(val)).second) { return true; } Logger::warn_or_error(warn, "Duplicate set entry: \"", val, "\""); return warn; }; } template T, typename... SetArgs> Callback auto set_callback_pointer(tsl::ordered_set& set, bool warn = false) { return [&set, warn](T const& val) -> bool { if (set.emplace(&val).second) { return true; } Logger::warn_or_error(warn, "Duplicate set entry: \"", &val, "\""); return warn; }; } template Key, typename Value, typename... MapArgs> Callback auto map_callback( tsl::ordered_map& map, Key const* key, bool warn = false ) { return [&map, key, warn](Value value) -> bool { if (map.emplace(key, std::move(value)).second) { return true; } Logger::warn_or_error(warn, "Duplicate map entry with key: \"", key, "\""); return warn; }; } template Callback auto map_callback( IndexedMap& map, Key const* key, bool warn = false ) { return [&map, key, warn](Value value) -> bool { if (key == nullptr) { Logger::error("Null key in map_callback"); return false; } Value& map_value = map[*key]; bool ret = true; if (map_value != Value {}) { Logger::warn_or_error(warn, "Duplicate map entry with key: \"", key, "\""); ret = warn; } map_value = std::move(value); return ret; }; } /* Often used for rotations which must be negated due to OpenVic's coordinate system being orientated * oppositely to Vic2's. */ template constexpr Callback auto negate_callback(Callback auto&& callback) { return [callback](T val) -> bool { return callback(-val); }; } /* Often used for map-space coordinates which must have their y-coordinate flipped due to OpenVic using the * top-left of the map as the origin as opposed Vic2 using the bottom-left. */ template constexpr Callback> auto flip_y_callback(Callback> auto&& callback, T height) { return [callback, height](vec2_t val) -> bool { val.y = height - val.y; return callback(val); }; } } } #undef FWD #undef MOV