aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/scripts/Condition.hpp
diff options
context:
space:
mode:
author hop311 <hop3114@gmail.com>2024-11-01 22:38:23 +0100
committer hop311 <hop3114@gmail.com>2024-11-01 22:38:23 +0100
commitfa0235d4eac01816a4832249f28ccadfb6dd6e40 (patch)
treeb1d3e6bb4b3a0accc42dd8e0038e51b134ad99ae /src/openvic-simulation/scripts/Condition.hpp
parent8defcd5daa1acd2c61aa1cd0a26478d472fed9b0 (diff)
Create basic condition script parsing and execution framework
Diffstat (limited to 'src/openvic-simulation/scripts/Condition.hpp')
-rw-r--r--src/openvic-simulation/scripts/Condition.hpp310
1 files changed, 127 insertions, 183 deletions
diff --git a/src/openvic-simulation/scripts/Condition.hpp b/src/openvic-simulation/scripts/Condition.hpp
index 1f4929a..c390b26 100644
--- a/src/openvic-simulation/scripts/Condition.hpp
+++ b/src/openvic-simulation/scripts/Condition.hpp
@@ -1,95 +1,37 @@
#pragma once
#include <ostream>
+#include <string>
#include <string_view>
#include <variant>
+#include "openvic-simulation/dataloader/NodeTools.hpp"
#include "openvic-simulation/types/EnumBitfield.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
namespace OpenVic {
- struct ConditionManager;
- struct ConditionScript;
- struct DefinitionManager;
-
- enum class value_type_t : uint8_t {
- NO_TYPE = 0,
- IDENTIFIER = 1 << 0,
- STRING = 1 << 1,
- BOOLEAN = 1 << 2,
- BOOLEAN_INT = 1 << 3,
- INTEGER = 1 << 4,
- REAL = 1 << 5,
- COMPLEX = 1 << 6,
- GROUP = 1 << 7,
- MAX_VALUE = (1 << 8) - 1
- };
-
- // Order matters in this enum, for the fallback system to work
- // smaller entities must have smaller integers associated!
- enum class scope_type_t : uint8_t { //TODO: maybe distinguish TRANSPARENT from NO_SCOPE
+ enum class scope_type_t : uint8_t {
NO_SCOPE = 0,
POP = 1 << 0,
PROVINCE = 1 << 1,
STATE = 1 << 2,
COUNTRY = 1 << 3,
- THIS = 1 << 4,
- FROM = 1 << 5,
- MAX_SCOPE = (1 << 6) - 1
- };
-
- enum class identifier_type_t : uint32_t {
- NO_IDENTIFIER = 0,
- VARIABLE = 1 << 0,
- GLOBAL_FLAG = 1 << 1,
- COUNTRY_FLAG = 1 << 2,
- PROVINCE_FLAG = 1 << 3,
- COUNTRY_TAG = 1 << 4,
- PROVINCE_ID = 1 << 5,
- REGION = 1 << 6,
- IDEOLOGY = 1 << 7,
- REFORM_GROUP = 1 << 8,
- REFORM = 1 << 9,
- ISSUE = 1 << 10,
- POP_TYPE = 1 << 11,
- POP_STRATA = 1 << 12,
- TECHNOLOGY = 1 << 13,
- INVENTION = 1 << 14,
- TECH_SCHOOL = 1 << 15,
- CULTURE = 1 << 16,
- CULTURE_GROUP = 1 << 17,
- RELIGION = 1 << 18,
- TRADE_GOOD = 1 << 19,
- BUILDING = 1 << 20,
- CASUS_BELLI = 1 << 21,
- GOVERNMENT_TYPE = 1 << 22,
- COUNTRY_EVENT_MODIFIER = 1 << 23,
- PROVINCE_EVENT_MODIFIER = 1 << 24,
- NATIONAL_VALUE = 1 << 25,
- CULTURE_UNION = 1 << 26, // same as COUNTRY_TAG but also accepts scope this_union
- CONTINENT = 1 << 27,
- CRIME = 1 << 28,
- TERRAIN = 1 << 29
+ THIS = 1 << 4, // Indicator bit for scope switching ("use the THIS scope", not a scope in and of itself)
+ FROM = 1 << 5, // Indicator bit for scope switching ("use the FROM scope", not a scope in and of itself)
+ FULL_SCOPE_MASK = (1 << 6) - 1, // All possible scope bits (including THIS and FROM)
+ ALL_SCOPES = POP | PROVINCE | STATE | COUNTRY // All real scopes (without THIS and FROM)
};
/* Allows enum types to be used with bitwise operators. */
- template<> struct enable_bitfield<value_type_t> : std::true_type {};
template<> struct enable_bitfield<scope_type_t> : std::true_type {};
- template<> struct enable_bitfield<identifier_type_t> : std::true_type {};
/* Returns true if the values have any bit in common. */
- inline constexpr bool share_value_type(value_type_t lhs, value_type_t rhs) {
- return (lhs & rhs) != value_type_t::NO_TYPE;
- }
inline constexpr bool share_scope_type(scope_type_t lhs, scope_type_t rhs) {
return (lhs & rhs) != scope_type_t::NO_SCOPE;
}
- inline constexpr bool share_identifier_type(identifier_type_t lhs, identifier_type_t rhs) {
- return (lhs & rhs) != identifier_type_t::NO_IDENTIFIER;
- }
-#define _BUILD_STRING(entry, share) \
- if (share(value, entry)) { \
+#define BUILD_STRING(entry) \
+ if (share_scope_type(value, entry)) { \
if (type_found) { \
stream << " | "; \
} else { \
@@ -98,179 +40,181 @@ namespace OpenVic {
stream << #entry; \
}
-#define BUILD_STRING(entry) _BUILD_STRING(entry, share_value_type)
-
- inline std::ostream& operator<<(std::ostream& stream, value_type_t value) {
- using enum value_type_t;
- if (value == NO_TYPE) {
- return stream << "[NO_TYPE]";
- }
- bool type_found = false;
- stream << '[';
- BUILD_STRING(IDENTIFIER);
- BUILD_STRING(STRING);
- BUILD_STRING(BOOLEAN);
- BUILD_STRING(BOOLEAN_INT);
- BUILD_STRING(INTEGER);
- BUILD_STRING(REAL);
- BUILD_STRING(COMPLEX);
- BUILD_STRING(GROUP);
- if (!type_found) {
- stream << "INVALID VALUE TYPE";
- }
- return stream << ']';
- }
-
-#undef BUILD_STRING
-#define BUILD_STRING(entry) _BUILD_STRING(entry, share_scope_type)
-
inline std::ostream& operator<<(std::ostream& stream, scope_type_t value) {
using enum scope_type_t;
+
if (value == NO_SCOPE) {
return stream << "[NO_SCOPE]";
}
+
bool type_found = false;
+
stream << '[';
+
BUILD_STRING(COUNTRY);
BUILD_STRING(STATE);
BUILD_STRING(PROVINCE);
BUILD_STRING(POP);
BUILD_STRING(THIS);
BUILD_STRING(FROM);
+
if (!type_found) {
stream << "INVALID SCOPE";
}
+
return stream << ']';
}
#undef BUILD_STRING
-#define BUILD_STRING(entry) _BUILD_STRING(entry, share_identifier_type)
- inline std::ostream& operator<<(std::ostream& stream, identifier_type_t value) {
- using enum identifier_type_t;
- if (value == NO_IDENTIFIER) {
- return stream << "[NO_IDENTIFIER]";
+ struct ConditionManager;
+ struct ConditionScript;
+ struct CountryDefinition;
+ struct CountryInstance;
+ struct ProvinceDefinition;
+ struct ProvinceInstance;
+ struct Pop;
+ struct GoodDefinition;
+ struct ProvinceSetModifier;
+ using Continent = ProvinceSetModifier;
+ struct Condition;
+ struct DefinitionManager;
+ struct InstanceManager;
+
+ struct ConditionNode {
+ friend struct ConditionManager;
+ friend struct ConditionScript;
+
+ // std::variant's default constructor sets it to the first type in its parameter list, so for argument_t and scope_t
+ // a default-constructed instance represents no_argument_t or no_scope_t.
+
+ struct no_argument_t {};
+ struct this_argument_t {};
+ struct from_argument_t {};
+ using integer_t = int64_t;
+ using argument_t = std::variant<
+ // No argument
+ no_argument_t,
+ // Script reference arguments
+ this_argument_t, from_argument_t,
+ // List argument
+ std::vector<ConditionNode>,
+ // Value arguments
+ bool, std::string, integer_t, fixed_point_t,
+ // Game object arguments
+ CountryDefinition const*, ProvinceDefinition const*, GoodDefinition const*, Continent const*
+ >;
+
+ static constexpr bool is_this_argument(argument_t const& argument) {
+ return std::holds_alternative<this_argument_t>(argument);
}
- bool type_found = false;
- stream << '[';
- BUILD_STRING(VARIABLE);
- BUILD_STRING(GLOBAL_FLAG);
- BUILD_STRING(COUNTRY_FLAG);
- BUILD_STRING(PROVINCE_FLAG);
- BUILD_STRING(COUNTRY_TAG);
- BUILD_STRING(PROVINCE_ID);
- BUILD_STRING(REGION);
- BUILD_STRING(IDEOLOGY);
- BUILD_STRING(REFORM_GROUP);
- BUILD_STRING(REFORM);
- BUILD_STRING(ISSUE);
- BUILD_STRING(POP_TYPE);
- BUILD_STRING(POP_STRATA);
- BUILD_STRING(TECHNOLOGY);
- BUILD_STRING(INVENTION);
- BUILD_STRING(TECH_SCHOOL);
- BUILD_STRING(CULTURE);
- BUILD_STRING(CULTURE_GROUP);
- BUILD_STRING(RELIGION);
- BUILD_STRING(TRADE_GOOD);
- BUILD_STRING(BUILDING);
- BUILD_STRING(CASUS_BELLI);
- BUILD_STRING(GOVERNMENT_TYPE);
- BUILD_STRING(COUNTRY_EVENT_MODIFIER);
- BUILD_STRING(PROVINCE_EVENT_MODIFIER);
- BUILD_STRING(NATIONAL_VALUE);
- BUILD_STRING(CULTURE_UNION);
- BUILD_STRING(CONTINENT);
- BUILD_STRING(CRIME);
- BUILD_STRING(TERRAIN);
- if (!type_found) {
- stream << "INVALID IDENTIFIER TYPE";
+
+ static constexpr bool is_from_argument(argument_t const& argument) {
+ return std::holds_alternative<from_argument_t>(argument);
}
- return stream << ']';
- }
-#undef BUILD_STRING
-#undef _BUILD_STRING
+ struct no_scope_t {};
+ using scope_t = std::variant<
+ no_scope_t,
+ CountryInstance const*,
+ ProvinceInstance const*,
+ Pop const*
+ >;
- struct Condition : HasIdentifier {
- friend struct ConditionManager;
- using enum identifier_type_t;
+ static constexpr bool is_no_scope(scope_t const& scope) {
+ return std::holds_alternative<no_scope_t>(scope);
+ }
private:
- const value_type_t PROPERTY(value_type);
- const scope_type_t PROPERTY(scope);
- const scope_type_t PROPERTY(scope_change);
- const identifier_type_t PROPERTY(key_identifier_type);
- const identifier_type_t PROPERTY(value_identifier_type);
+ Condition const* PROPERTY(condition);
+ argument_t PROPERTY(argument);
- Condition(
- std::string_view new_identifier, value_type_t new_value_type, scope_type_t new_scope,
- scope_type_t new_scope_change, identifier_type_t new_key_identifier_type,
- identifier_type_t new_value_identifier_type
+ ConditionNode(
+ Condition const* new_condition = nullptr, argument_t&& new_argument = no_argument_t {}
);
public:
- Condition(Condition&&) = default;
+ ConditionNode(ConditionNode&&) = default;
+ ConditionNode& operator=(ConditionNode&&) = default;
+
+ constexpr bool is_initialised() const {
+ return condition != nullptr;
+ }
+
+ bool execute(
+ InstanceManager const& instance_manager, scope_t const& current_scope, scope_t const& this_scope,
+ scope_t const& from_scope
+ ) const;
};
- struct ConditionNode {
+ struct Condition : HasIdentifier {
friend struct ConditionManager;
- friend struct ConditionScript;
- using string_t = std::string;
- using boolean_t = bool;
- using double_boolean_t = std::pair<bool, bool>;
- using integer_t = uint64_t;
- using real_t = fixed_point_t;
- using identifier_real_t = std::pair<std::string, real_t>;
- using condition_list_t = std::vector<ConditionNode>;
- using value_t = std::variant<
- string_t, boolean_t, double_boolean_t, integer_t, real_t, identifier_real_t, condition_list_t
+ using parse_callback_t = NodeTools::callback_t<
+ // bool(definition_manager, current_scope, this_scope, from_scope, node, callback)
+ DefinitionManager const&, scope_type_t, scope_type_t, scope_type_t, ast::NodeCPtr,
+ NodeTools::callback_t<ConditionNode::argument_t&&>
+ >;
+ using execute_callback_t = NodeTools::callback_t<
+ // bool(instance_manager, current_scope, this_scope, from_scope, argument)
+ InstanceManager const&, ConditionNode::scope_t const&, ConditionNode::scope_t const&,
+ ConditionNode::scope_t const&, ConditionNode::argument_t const&
>;
private:
- Condition const* PROPERTY(condition);
- value_t PROPERTY(value);
- HasIdentifier const* PROPERTY(condition_key_item);
- HasIdentifier const* PROPERTY(condition_value_item);
- bool PROPERTY_CUSTOM_PREFIX(valid, is);
+ parse_callback_t PROPERTY(parse_callback);
+ execute_callback_t PROPERTY(execute_callback);
- ConditionNode(
- Condition const* new_condition = nullptr, value_t&& new_value = 0,
- bool new_valid = false,
- HasIdentifier const* new_condition_key_item = nullptr,
- HasIdentifier const* new_condition_value_item = nullptr
+ Condition(
+ std::string_view new_identifier,
+ parse_callback_t&& new_parse_callback,
+ execute_callback_t&& new_execute_callback
);
+
+ public:
+ Condition(Condition&&) = default;
};
struct ConditionManager {
private:
CaseInsensitiveIdentifierRegistry<Condition> IDENTIFIER_REGISTRY(condition);
- Condition const* root_condition = nullptr;
+ Condition const* PROPERTY(root_condition);
bool add_condition(
- std::string_view identifier, value_type_t value_type, scope_type_t scope,
- scope_type_t scope_change = scope_type_t::NO_SCOPE,
- identifier_type_t key_identifier_type = identifier_type_t::NO_IDENTIFIER,
- identifier_type_t value_identifier_type = identifier_type_t::NO_IDENTIFIER
+ std::string_view identifier,
+ Condition::parse_callback_t&& parse_callback,
+ Condition::execute_callback_t&& execute_callback
);
- NodeTools::callback_t<std::string_view> expect_parse_identifier(
- DefinitionManager const& definition_manager, identifier_type_t identifier_type,
- NodeTools::callback_t<HasIdentifier const*> callback
+ template<
+ scope_type_t CHANGE_SCOPE = scope_type_t::NO_SCOPE,
+ scope_type_t ALLOWED_SCOPES = scope_type_t::ALL_SCOPES,
+ bool TOP_SCOPE = false
+ >
+ static bool _parse_condition_node_list_callback(
+ DefinitionManager const& definition_manager, scope_type_t current_scope, scope_type_t this_scope,
+ scope_type_t from_scope, ast::NodeCPtr node, NodeTools::callback_t<ConditionNode::argument_t&&> callback
+ );
+
+ NodeTools::Callback<Condition const&, ast::NodeCPtr> auto expect_condition_node(
+ DefinitionManager const& definition_manager, scope_type_t current_scope, scope_type_t this_scope,
+ scope_type_t from_scope, NodeTools::Callback<ConditionNode&&> auto callback
) const;
- NodeTools::node_callback_t expect_condition_node(
- DefinitionManager const& definition_manager, Condition const& condition, scope_type_t current_scope,
- scope_type_t this_scope, scope_type_t from_scope, NodeTools::callback_t<ConditionNode&&> callback
+ NodeTools::NodeCallback auto expect_condition_node_list_and_length(
+ DefinitionManager const& definition_manager, scope_type_t current_scope, scope_type_t this_scope,
+ scope_type_t from_scope, NodeTools::Callback<ConditionNode&&> auto callback,
+ NodeTools::LengthCallback auto length_callback, bool top_scope = false
) const;
- NodeTools::node_callback_t expect_condition_node_list(
+ NodeTools::NodeCallback auto expect_condition_node_list(
DefinitionManager const& definition_manager, scope_type_t current_scope, scope_type_t this_scope,
- scope_type_t from_scope, NodeTools::callback_t<ConditionNode&&> callback, bool top_scope = false
+ scope_type_t from_scope, NodeTools::Callback<ConditionNode&&> auto callback, bool top_scope = false
) const;
public:
+ ConditionManager();
+
bool setup_conditions(DefinitionManager const& definition_manager);
NodeTools::node_callback_t expect_condition_script(