aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvic-simulation')
-rw-r--r--src/openvic-simulation/vm/Codegen.cpp139
-rw-r--r--src/openvic-simulation/vm/Codegen.hpp40
2 files changed, 167 insertions, 12 deletions
diff --git a/src/openvic-simulation/vm/Codegen.cpp b/src/openvic-simulation/vm/Codegen.cpp
index b84078e..675bc2c 100644
--- a/src/openvic-simulation/vm/Codegen.cpp
+++ b/src/openvic-simulation/vm/Codegen.cpp
@@ -1,16 +1,18 @@
#include "Codegen.hpp"
#include <cctype>
+#include <cstring>
#include <string_view>
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
+#include <tsl/ordered_map.h>
+
#include <dryad/node.hpp>
#include <dryad/tree.hpp>
#include <range/v3/algorithm/equal.hpp>
-#include "tsl/ordered_map.h"
#include <lauf/asm/builder.h>
using namespace OpenVic::Vm;
@@ -23,8 +25,113 @@ bool ichar_equals(char a, char b) {
return std::tolower(static_cast<unsigned char>(a)) == std::tolower(static_cast<unsigned char>(b));
}
-void Codegen::generate_effect_from(Parser const& parser, Node* node) {
+Codegen::Codegen(ovdl::v2script::Parser const& parser, const char* module_name, lauf_asm_build_options options)
+ : _parser(parser), _module(module_name), _builder(options) {
+ intern_scopes();
+}
+
+Codegen::Codegen(ovdl::v2script::Parser const& parser, Module&& module, AsmBuilder&& builder)
+ : _parser(parser), _module(std::move(module)), _builder(std::move(builder)) {
+ intern_scopes();
+}
+
+void Codegen::intern_scopes() {
+ _has_top_level_province_scopes = static_cast<bool>(_parser.find_intern("province_event"sv));
+ _has_top_level_country_scopes = static_cast<bool>(_parser.find_intern("country_event"sv)) ||
+ static_cast<bool>(_parser.find_intern("political_decisions"sv));
+
+#define PUSH_INTERN(CONTAINTER, NAME) \
+ [&](auto&& scope_name) { \
+ if (scope_name) \
+ CONTAINTER.insert(scope_name); \
+ }(_parser.find_intern(#NAME##sv))
+
+ PUSH_INTERN(_all_scopes, THIS);
+ PUSH_INTERN(_all_scopes, FROM);
+ PUSH_INTERN(_all_scopes, from);
+ PUSH_INTERN(_all_scopes, cultural_union);
+
+ // Country Scope
+ PUSH_INTERN(_country_scopes, capital_scope);
+ PUSH_INTERN(_country_scopes, overlord);
+ PUSH_INTERN(_country_scopes, sphere_owner);
+ // Country Scope Random
+ PUSH_INTERN(_country_scopes, random_country);
+ PUSH_INTERN(_country_scopes, random_owned);
+ PUSH_INTERN(_country_scopes, random_pop);
+ // Country Scope Iterative
+ PUSH_INTERN(_country_scopes, all_core);
+ PUSH_INTERN(_country_scopes, any_country);
+ PUSH_INTERN(_country_scopes, any_core);
+ PUSH_INTERN(_country_scopes, any_greater_power);
+ PUSH_INTERN(_country_scopes, any_neighbor_country);
+ PUSH_INTERN(_country_scopes, any_owned_province);
+ PUSH_INTERN(_country_scopes, any_pop);
+ PUSH_INTERN(_country_scopes, any_sphere_member);
+ PUSH_INTERN(_country_scopes, any_state);
+ PUSH_INTERN(_country_scopes, any_substate);
+ PUSH_INTERN(_country_scopes, war_countries);
+
+ // Province Scope
+ PUSH_INTERN(_province_scopes, controller);
+ PUSH_INTERN(_province_scopes, owner);
+ PUSH_INTERN(_province_scopes, state_scope);
+ // Province Scope Random
+ PUSH_INTERN(_province_scopes, random_neighbor_province);
+ PUSH_INTERN(_province_scopes, random_empty_neighbor_province);
+ // Province Scope Iterative
+ PUSH_INTERN(_province_scopes, any_core);
+ PUSH_INTERN(_province_scopes, any_neighbor_province);
+ PUSH_INTERN(_province_scopes, any_pop);
+
+ // Pop Scope
+ PUSH_INTERN(_pop_scopes, country);
+ PUSH_INTERN(_pop_scopes, location);
+
+
+#undef PUSH_INTERN
+}
+
+constexpr auto any_ = "any_"sv;
+constexpr auto all_ = "all_"sv;
+constexpr auto war_countries = "war_countries"sv;
+
+bool Codegen::is_iterative_scope(scope_execution_type execution_type, scope_type active_scope, ovdl::symbol<char> name) const {
+ return std::strncmp(name.c_str(), any_.data(), any_.size()) == 0 ||
+ std::strncmp(name.c_str(), all_.data(), all_.size()) == 0 ||
+ std::strncmp(name.c_str(), war_countries.data(), war_countries.size()) == 0;
+}
+
+bool Codegen::is_scope_for(scope_execution_type execution_type, scope_type active_scope, ovdl::symbol<char> name) const {
+ if (_all_scopes.contains(name)) {
+ return true;
+ }
+
+ switch (active_scope) {
+ case scope_type::Country:
+ if (_country_scopes.contains(name)) {
+ return true;
+ }
+ break;
+ case scope_type::State: break;
+ case scope_type::Province:
+ if (_province_scopes.contains(name)) {
+ return true;
+ }
+ break;
+ case scope_type::Pop:
+ if (_pop_scopes.contains(name)) {
+ return true;
+ }
+ break;
+ }
+
+ return false;
+}
+
+void Codegen::generate_effect_from(Codegen::scope_type type, Node* node) {
bool is_prepping_args = false;
+ Codegen::scope_type current_scope = type;
tsl::ordered_map<std::string_view, std::string_view> prepped_arguments;
dryad::visit_tree(
@@ -35,10 +142,19 @@ void Codegen::generate_effect_from(Parser const& parser, Node* node) {
return;
}
+ if (is_prepping_args) {
+ visitor(statement->right());
+ return;
+ }
+
auto const* right = dryad::node_try_cast<FlatValue>(statement->right());
if (!right) {
- is_prepping_args = true; // TODO: determine if scope or list-arg effect
+ using enum Codegen::scope_execution_type;
+ bool is_iterative = is_iterative_scope(Effect, current_scope, left->value());
+ if (is_iterative) {}
+ is_prepping_args = is_scope_for(Effect, current_scope, left->value());
visitor(right);
+ if (is_iterative) {}
} else if (ranges::equal(right->value().view(), "yes"sv, ichar_equals)) {
// TODO: insert vic2 bytecode scope object address here
// TODO: calls a builtin for Victoria 2 effects?
@@ -48,12 +164,21 @@ void Codegen::generate_effect_from(Parser const& parser, Node* node) {
},
[&](FlatValue* value) {
// TODO: handle right side
+ },
+ [&](dryad::traverse_event ev, ListValue* value) {
+ if (is_prepping_args && ev == dryad::traverse_event::exit) {
+ // TODO: arguments have been prepared, call effect function
+ is_prepping_args = false;
+ } else if (!is_prepping_args && ev == dryad::traverse_event::enter) {
+ // TODO: this is a scope
+ }
}
);
}
-void Codegen::generate_condition_from(Parser const& parser, Node* node) {
+void Codegen::generate_condition_from(Codegen::scope_type type, Node* node) {
bool is_prepping_args = false;
+ Codegen::scope_type current_scope = type;
tsl::ordered_map<std::string_view, std::string_view> prepped_arguments;
dryad::visit_tree(
@@ -66,8 +191,12 @@ void Codegen::generate_condition_from(Parser const& parser, Node* node) {
auto const* right = dryad::node_try_cast<FlatValue>(statement->right());
if (!right) {
- is_prepping_args = true; // TODO: determine if scope or list-arg effect
+ using enum Codegen::scope_execution_type;
+ bool is_iterative = is_iterative_scope(Trigger, current_scope, left->value());
+ if (is_iterative) {}
+ is_prepping_args = is_scope_for(Trigger, current_scope, left->value());
visitor(right);
+ if (is_iterative) {}
} else if (ranges::equal(right->value().view(), "yes"sv, ichar_equals)) {
// TODO: insert vic2 bytecode scope object address here
// TODO: calls a builtin for Victoria 2 triggers?
diff --git a/src/openvic-simulation/vm/Codegen.hpp b/src/openvic-simulation/vm/Codegen.hpp
index 1670718..b50e5f7 100644
--- a/src/openvic-simulation/vm/Codegen.hpp
+++ b/src/openvic-simulation/vm/Codegen.hpp
@@ -1,5 +1,8 @@
#pragma once
+#include <unordered_set>
+
+#include <openvic-dataloader/detail/SymbolIntern.hpp>
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
#include <openvic-dataloader/v2script/Parser.hpp>
@@ -9,10 +12,12 @@
namespace OpenVic::Vm {
struct Codegen {
- Codegen(const char* module_name, lauf_asm_build_options options = lauf_asm_default_build_options)
- : _module(module_name), _builder(options) {}
+ Codegen(
+ ovdl::v2script::Parser const& parser, const char* module_name,
+ lauf_asm_build_options options = lauf_asm_default_build_options
+ );
- Codegen(Module&& module, AsmBuilder&& builder) : _module(std::move(module)), _builder(std::move(builder)) {}
+ Codegen(ovdl::v2script::Parser const& parser, Module&& module, AsmBuilder&& builder);
operator lauf_asm_module*() {
return _module;
@@ -46,6 +51,8 @@ namespace OpenVic::Vm {
return _builder;
}
+ void intern_scopes();
+
lauf_asm_block* create_block(size_t input_count) {
return lauf_asm_declare_block(_builder, input_count);
}
@@ -54,11 +61,17 @@ namespace OpenVic::Vm {
lauf_asm_build_block(*this, block);
}
- lauf_asm_function* create_effect_function(ovdl::v2script::Parser const& parser, ovdl::v2script::ast::Node* node);
- lauf_asm_function* create_condition_function(ovdl::v2script::Parser const& parser, ovdl::v2script::ast::Node* node);
+ enum class scope_execution_type : std::uint8_t { Effect, Trigger };
+ enum class scope_type : std::uint8_t { Country, State, Province, Pop };
+
+ bool is_iterative_scope(scope_execution_type execution_type, scope_type active_scope, ovdl::symbol<char> name) const;
+ bool is_scope_for(scope_execution_type execution_type, scope_type active_scope, ovdl::symbol<char> name) const;
- void generate_effect_from(ovdl::v2script::Parser const& parser, ovdl::v2script::ast::Node* node);
- void generate_condition_from(ovdl::v2script::Parser const& parser, ovdl::v2script::ast::Node* node);
+ lauf_asm_function* create_effect_function(scope_type type, ovdl::v2script::ast::Node* node);
+ lauf_asm_function* create_condition_function(scope_type type, ovdl::v2script::ast::Node* node);
+
+ void generate_effect_from(scope_type type, ovdl::v2script::ast::Node* node);
+ void generate_condition_from(scope_type type, ovdl::v2script::ast::Node* node);
// Bytecode instructions //
void inst_push_scope_this();
@@ -135,8 +148,21 @@ namespace OpenVic::Vm {
void inst_push_get_province_modifier(const char* modifier_id);
// Bytecode instructions //
+ struct symbol_hash {
+ std::size_t operator()(const ovdl::symbol<char>& s) const noexcept {
+ return std::hash<const void*> {}(static_cast<const void*>(s.c_str()));
+ }
+ };
+
private:
Module _module;
AsmBuilder _builder;
+ ovdl::v2script::Parser const& _parser;
+ std::unordered_set<ovdl::symbol<char>, symbol_hash> _all_scopes;
+ std::unordered_set<ovdl::symbol<char>, symbol_hash> _country_scopes;
+ std::unordered_set<ovdl::symbol<char>, symbol_hash> _province_scopes;
+ std::unordered_set<ovdl::symbol<char>, symbol_hash> _pop_scopes;
+ bool _has_top_level_country_scopes;
+ bool _has_top_level_province_scopes;
};
}