diff options
Diffstat (limited to 'src/openvic-simulation')
-rw-r--r-- | src/openvic-simulation/vm/Builtin.cpp | 153 | ||||
-rw-r--r-- | src/openvic-simulation/vm/Builtin.hpp | 109 | ||||
-rw-r--r-- | src/openvic-simulation/vm/Codegen.cpp | 401 | ||||
-rw-r--r-- | src/openvic-simulation/vm/Codegen.hpp | 25 | ||||
-rw-r--r-- | src/openvic-simulation/vm/VirtualMachine.hpp | 24 |
5 files changed, 387 insertions, 325 deletions
diff --git a/src/openvic-simulation/vm/Builtin.cpp b/src/openvic-simulation/vm/Builtin.cpp new file mode 100644 index 0000000..c5c62e9 --- /dev/null +++ b/src/openvic-simulation/vm/Builtin.cpp @@ -0,0 +1,153 @@ +#include "vm/Builtin.hpp" + +#include "InstanceManager.hpp" +#include "vm/Codegen.hpp" +#include <lauf/runtime/builtin.h> +#include <lauf/runtime/memory.h> +#include <lauf/runtime/process.h> +#include <lauf/runtime/value.h> + +OpenVic::Asm::scope_variant* +get_keyword_scope(OpenVic::InstanceManager* instance_manager, const char* keyword, OpenVic::Vm::Codegen::scope_type type) { + // TODO: get scope native pointer from name and type + return nullptr; +} + +bool execute_effect( + OpenVic::InstanceManager* instance_manager, const char* effect_id, OpenVic::Asm::scope_variant& scope, + OpenVic::Asm::argument* arguments, std::size_t arg_count +) { + // TODO: execute effect based on id, scope, and arguments + return true; +} + +bool execute_trigger( + OpenVic::InstanceManager* instance_manager, const char* trigger_id, OpenVic::Asm::scope_variant& scope, + OpenVic::Asm::argument* arguments, std::size_t arg_count, bool* result +) { + // TODO: execute trigger based on id, scope, and arguments + return true; +} + +LAUF_RUNTIME_BUILTIN(call_effect, 3, 0, LAUF_RUNTIME_BUILTIN_DEFAULT, "call_effect", nullptr) { + auto user_data = lauf_runtime_get_vm_user_data(process); + if (user_data == nullptr) { + return lauf_runtime_panic(process, "invalid user data"); + } + auto vm_data = static_cast<OpenVic::Vm::VmUserData*>(user_data); + + auto effect_name_addr = vstack_ptr[0].as_address; + auto scope_ptr = static_cast<OpenVic::Asm::scope_variant*>(vstack_ptr[1].as_native_ptr); + auto argument_array_addr = vstack_ptr[2].as_address; + + auto effect_name = lauf_runtime_get_cstr(process, effect_name_addr); + if (effect_name == nullptr) { + return lauf_runtime_panic(process, "invalid effect name address"); + } + + lauf_runtime_allocation array_allocation; + if (!lauf_runtime_get_allocation(process, argument_array_addr, &array_allocation)) { + return lauf_runtime_panic(process, "invalid arguments address"); + } + + std::size_t count = array_allocation.size / lauf_asm_type_value.layout.size; + + auto argument_array = + static_cast<OpenVic::Asm::argument*>(lauf_runtime_get_mut_ptr(process, argument_array_addr, { 1, 1 })); + + if (!execute_effect(vm_data->instance_manager, effect_name, *scope_ptr, argument_array, count)) { + return lauf_runtime_panic(process, "effect could not be found"); + } + + vstack_ptr += 3; + LAUF_RUNTIME_BUILTIN_DISPATCH; +} + +LAUF_RUNTIME_BUILTIN(call_trigger, 3, 1, LAUF_RUNTIME_BUILTIN_DEFAULT, "call_trigger", &call_effect) { + auto user_data = lauf_runtime_get_vm_user_data(process); + if (user_data == nullptr) { + return lauf_runtime_panic(process, "invalid user data"); + } + auto vm_data = static_cast<OpenVic::Vm::VmUserData*>(user_data); + + auto trigger_name_addr = vstack_ptr[0].as_address; + auto scope_ptr = vstack_ptr[1].as_native_ptr; + auto argument_array_addr = vstack_ptr[2].as_address; + + auto effect_name = lauf_runtime_get_cstr(process, trigger_name_addr); + if (effect_name == nullptr) { + return lauf_runtime_panic(process, "invalid trigger name address"); + } + + lauf_runtime_allocation array_allocation; + if (!lauf_runtime_get_allocation(process, argument_array_addr, &array_allocation)) { + return lauf_runtime_panic(process, "invalid arguments address"); + } + + std::size_t count = array_allocation.size / lauf_asm_type_value.layout.size; + + auto argument_array = + static_cast<OpenVic::Asm::argument*>(lauf_runtime_get_mut_ptr(process, argument_array_addr, { 1, 1 })); + + bool trigger_result; + + if (!execute_trigger( + static_cast<OpenVic::InstanceManager*>(user_data), effect_name, + *static_cast<OpenVic::Asm::scope_variant*>(scope_ptr), argument_array, count, &trigger_result + )) { + return lauf_runtime_panic(process, "trigger could not be found"); + } + + vstack_ptr += 2; + + vstack_ptr[0].as_sint = trigger_result; + + LAUF_RUNTIME_BUILTIN_DISPATCH; +} + +LAUF_RUNTIME_BUILTIN( + translate_address_to_pointer, 1, 1, LAUF_RUNTIME_BUILTIN_DEFAULT, "translate_address_to_pointer", &call_trigger +) { + auto address = vstack_ptr[0].as_address; + + auto ptr = lauf_runtime_get_const_ptr(process, address, { 0, 1 }); + if (ptr == nullptr) { + return lauf_runtime_panic(process, "invalid address"); + } + vstack_ptr[0].as_native_ptr = (void*)ptr; + + LAUF_RUNTIME_BUILTIN_DISPATCH; +} + +LAUF_RUNTIME_BUILTIN( + translate_address_to_string, 1, 1, LAUF_RUNTIME_BUILTIN_DEFAULT, "translate_address_to_string", + &translate_address_to_pointer +) { + auto address = vstack_ptr[0].as_address; + + auto ptr = lauf_runtime_get_cstr(process, address); + if (ptr == nullptr) { + return lauf_runtime_panic(process, "invalid address"); + } + vstack_ptr[0].as_native_ptr = (void*)ptr; + + LAUF_RUNTIME_BUILTIN_DISPATCH; +} + +LAUF_RUNTIME_BUILTIN(load_scope_ptr, 1, 1, LAUF_RUNTIME_BUILTIN_DEFAULT, "load_scope_ptr", &translate_address_to_string) { + auto user_data = lauf_runtime_get_vm_user_data(process); + if (user_data == nullptr) { + return lauf_runtime_panic(process, "invalid user data"); + } + auto vm_data = static_cast<OpenVic::Vm::VmUserData*>(user_data); + + auto scope_ref_position = vstack_ptr[0].as_uint; + + if (scope_ref_position >= vm_data->scope_references.size()) { + return lauf_runtime_panic(process, "invalid scope reference value"); + } + + vstack_ptr[0].as_native_ptr = &vm_data->scope_references[scope_ref_position]; + + LAUF_RUNTIME_BUILTIN_DISPATCH; +} diff --git a/src/openvic-simulation/vm/Builtin.hpp b/src/openvic-simulation/vm/Builtin.hpp new file mode 100644 index 0000000..9f72350 --- /dev/null +++ b/src/openvic-simulation/vm/Builtin.hpp @@ -0,0 +1,109 @@ +#pragma once + +#include <cstdint> +#include <variant> + +#include "InstanceManager.hpp" +#include "types/fixed_point/FixedPoint.hpp" + +extern "C" { + typedef struct lauf_runtime_builtin lauf_runtime_builtin; + + // This builtin takes three arguments: + // * vstack_ptr[0] is an address of the name of the effect + // * vstack_ptr[1] is an address of the scope reference to apply the effect by + // * vstack_ptr[2] is an address to an array of pointers to the arguments for the effect + extern const lauf_runtime_builtin call_effect; + + // This builtin takes three arguments: + // * vstack_ptr[0] is an address of the name of the trigger + // * vstack_ptr[1] is an address of the scope to apply the trigger by + // * vstack_ptr[2] is an address to an array of pointers to the arguments for the trigger + // Returns whether the trigger evaluated to true + extern const lauf_runtime_builtin call_trigger; + + // Translates a lauf address into the native pointer representation. + // It takes one argument, which is the address, and returns one argument, which is the pointer. + extern const lauf_runtime_builtin translate_address_to_pointer; + // As above, but translates to a C string. + extern const lauf_runtime_builtin translate_address_to_string; + + // This builtin takes three arguments: + // * vstack_ptr[0] is a uint for the position of the pointer variant in scope_references + // Returns scope native pointer + extern const lauf_runtime_builtin load_scope_ptr; +} + +namespace OpenVic::Asm { + using scope_variant = std::variant<std::monostate>; + + struct argument { + const char* key; + + union { + const char* as_cstr; + const scope_variant* as_scope; + std::uint64_t as_uint; + std::int64_t as_int; + const void* as_ptr; + } value; + + enum class type_t : std::uint8_t { // + cstring, + scope, + uint, + int_, + ptr, + fixed_point + } type; + + const char* val_cstr() const { + if (type != type_t::cstring) { + return nullptr; + } + return value.as_cstr; + } + + const scope_variant* val_scope() const { + if (type != type_t::scope) { + return nullptr; + } + return value.as_scope; + } + + std::uint64_t val_uint() const { + if (type != type_t::uint) { + return 0; + } + return value.as_uint; + } + + std::int64_t val_int() const { + if (type != type_t::int_) { + return 0; + } + return value.as_int; + } + + const void* val_ptr() const { + if (type != type_t::ptr) { + return nullptr; + } + return value.as_ptr; + } + + OpenVic::fixed_point_t val_fixed() const { + if (type != type_t::fixed_point) { + return 0; + } + return OpenVic::fixed_point_t(value.as_int); + } + }; +} + +namespace OpenVic::Vm { + struct VmUserData { + std::vector<Asm::scope_variant> scope_references; + InstanceManager* instance_manager; + }; +} diff --git a/src/openvic-simulation/vm/Codegen.cpp b/src/openvic-simulation/vm/Codegen.cpp index 34a1093..a31f6c5 100644 --- a/src/openvic-simulation/vm/Codegen.cpp +++ b/src/openvic-simulation/vm/Codegen.cpp @@ -6,7 +6,6 @@ #include <cstring> #include <string_view> #include <unordered_map> -#include <variant> #include <openvic-dataloader/detail/SymbolIntern.hpp> #include <openvic-dataloader/detail/Utility.hpp> @@ -21,8 +20,8 @@ #include <range/v3/algorithm/equal.hpp> #include <range/v3/algorithm/reverse.hpp> -#include "InstanceManager.hpp" #include "types/fixed_point/FixedPoint.hpp" +#include "vm/Builtin.hpp" #include <lauf/asm/builder.h> #include <lauf/asm/module.h> #include <lauf/runtime/builtin.h> @@ -40,194 +39,16 @@ bool ichar_equals(char a, char b) { return std::tolower(static_cast<unsigned char>(a)) == std::tolower(static_cast<unsigned char>(b)); } -using scope_variant = std::variant<std::monostate>; -using argument_variant = std::variant<std::monostate>; -using argument_map = std::unordered_map<std::string_view, argument_variant>; - -static constexpr auto argument_size = 32; - -struct ov_asm_argument { - const char* key; - - union { - const char* as_cstr; - const scope_variant* as_scope; - std::uint64_t as_uint; - std::int64_t as_int; - const void* as_ptr; - } value; - - enum class type_t : std::uint8_t { // - cstring, - scope, - uint, - int_, - ptr, - fixed_point - } type; - - const char* val_cstr() const { - if (type != type_t::cstring) { - return nullptr; - } - return value.as_cstr; - } - - const scope_variant* val_scope() const { - if (type != type_t::scope) { - return nullptr; - } - return value.as_scope; - } - - std::uint64_t val_uint() const { - if (type != type_t::uint) { - return 0; - } - return value.as_uint; - } - - std::int64_t val_int() const { - if (type != type_t::int_) { - return 0; - } - return value.as_int; - } - - const void* val_ptr() const { - if (type != type_t::ptr) { - return nullptr; - } - return value.as_ptr; - } - - OpenVic::fixed_point_t val_fixed() const { - if (type != type_t::fixed_point) { - return 0; - } - return OpenVic::fixed_point_t(value.as_int); - } -}; - -bool execute_effect( - OpenVic::InstanceManager* instance_manager, const char* effect_id, scope_variant& scope, ov_asm_argument*, - std::size_t arg_count -) { - return true; -} - -ov_asm_argument arguments[argument_size]; - -// This builtin takes three arguments: -// * vstack_ptr[0] is an address of the name of the effect -// * vstack_ptr[1] is an address of the scope reference to apply the effect by -// * vstack_ptr[2] is an address to an array of pointers to the arguments for the effect -LAUF_RUNTIME_BUILTIN(call_effect, 3, 0, LAUF_RUNTIME_BUILTIN_DEFAULT, "call_effect", nullptr) { - auto user_data = lauf_runtime_get_vm_user_data(process); - if (user_data == nullptr) { - return lauf_runtime_panic(process, "invalid user data"); - } - - auto effect_name_addr = vstack_ptr[0].as_address; - auto scope_addr = vstack_ptr[1].as_address; - auto argument_array_addr = vstack_ptr[2].as_address; - - auto effect_name = lauf_runtime_get_cstr(process, effect_name_addr); - if (effect_name == nullptr) { - return lauf_runtime_panic(process, "invalid effect name address"); - } - - auto scope_ptr = lauf_runtime_get_mut_ptr(process, scope_addr, { 0, 1 }); - if (scope_ptr == nullptr) { - return lauf_runtime_panic(process, "invalid scope address"); - } - - lauf_runtime_allocation array_allocation; - if (!lauf_runtime_get_allocation(process, argument_array_addr, &array_allocation)) { - return lauf_runtime_panic(process, "invalid arguments address"); - } - - std::size_t count = array_allocation.size / lauf_asm_type_value.layout.size; - if (count > argument_size) { - return lauf_runtime_panic(process, "too many arguments"); - } - - auto argument_array = static_cast<ov_asm_argument*>(lauf_runtime_get_mut_ptr(process, argument_array_addr, { 1, 1 })); - - if (!execute_effect( - static_cast<OpenVic::InstanceManager*>(user_data), effect_name, *static_cast<scope_variant*>(scope_ptr), - argument_array, count - )) { - return lauf_runtime_panic(process, "effect could not be found"); - } +Codegen::Codegen( + ovdl::v2script::Parser const& parser, OpenVic::InstanceManager* instance_manager, const char* module_name, + lauf_asm_build_options options +) + : _parser(parser), _instance_manager(instance_manager), _module(module_name), _builder(options) {} - vstack_ptr += 3; - LAUF_RUNTIME_BUILTIN_DISPATCH; -} - -// This builtin takes three arguments: -// * vstack_ptr[0] is an address of the name of the trigger -// * vstack_ptr[1] is an address of the scope to apply the trigger by -// * vstack_ptr[2] is an address to an array of pointers to the arguments for the trigger -// Returns whether the trigger evaluated to true -LAUF_RUNTIME_BUILTIN(call_trigger, 3, 1, LAUF_RUNTIME_BUILTIN_DEFAULT, "call_trigger", &call_effect) { - auto effect_name_addr = vstack_ptr[0].as_address; - auto scope_addr = vstack_ptr[1].as_address; - auto argument_array_addr = vstack_ptr[2].as_address; - - auto effect_name = lauf_runtime_get_cstr(process, effect_name_addr); - if (effect_name == nullptr) { - return lauf_runtime_panic(process, "invalid address"); - } - - - auto argument_addresses = - static_cast<lauf_runtime_value*>(lauf_runtime_get_mut_ptr(process, argument_array_addr, { 1, 1 })); - - // TODO: call trigger by name - - vstack_ptr[0].as_sint = 1; - - vstack_ptr += 2; - LAUF_RUNTIME_BUILTIN_DISPATCH; -} - -// Translates a lauf address into the native pointer representation. -// It takes one argument, which is the address, and returns one argument, which is the pointer. -LAUF_RUNTIME_BUILTIN( - translate_address_to_pointer, 1, 1, LAUF_RUNTIME_BUILTIN_DEFAULT, "translate_address_to_pointer", &call_trigger -) { - auto address = vstack_ptr[0].as_address; - - auto ptr = lauf_runtime_get_const_ptr(process, address, { 0, 1 }); - if (ptr == nullptr) { - return lauf_runtime_panic(process, "invalid address"); - } - vstack_ptr[0].as_native_ptr = (void*)ptr; - - LAUF_RUNTIME_BUILTIN_DISPATCH; -} -// As above, but translates to a C string. -LAUF_RUNTIME_BUILTIN( - translate_address_to_string, 1, 1, LAUF_RUNTIME_BUILTIN_DEFAULT, "translate_address_to_string", - &translate_address_to_pointer -) { - auto address = vstack_ptr[0].as_address; - - auto ptr = lauf_runtime_get_cstr(process, address); - if (ptr == nullptr) { - return lauf_runtime_panic(process, "invalid address"); - } - vstack_ptr[0].as_native_ptr = (void*)ptr; - - LAUF_RUNTIME_BUILTIN_DISPATCH; -} - -Codegen::Codegen(ovdl::v2script::Parser const& parser, const char* module_name, lauf_asm_build_options options) - : _parser(parser), _module(module_name), _builder(options) {} - -Codegen::Codegen(ovdl::v2script::Parser const& parser, Module&& module, AsmBuilder&& builder) - : _parser(parser), _module(std::move(module)), _builder(std::move(builder)) {} +Codegen::Codegen( + ovdl::v2script::Parser const& parser, OpenVic::InstanceManager* instance_manager, Module&& module, AsmBuilder&& builder +) + : _parser(parser), _instance_manager(instance_manager), _module(std::move(module)), _builder(std::move(builder)) {} static constexpr auto any_ = "any_"sv; static constexpr auto all_ = "all_"sv; @@ -243,6 +64,10 @@ bool Codegen::is_iterative_scope(scope_execution_type execution_type, scope_type Codegen::scope_type Codegen::get_scope_type_for(scope_execution_type execution_type, ovdl::symbol<char> name) const { using enum scope_type; + if (!name) { + return None; + } + #define FIND_SCOPE(SCOPE_TYPE, NAME) \ if (_parser.find_intern(#NAME##sv) == name) \ return SCOPE_TYPE @@ -303,7 +128,7 @@ void Codegen::generate_effect_from(scope_type type, Node* node) { bool is_arguments = false; std::unordered_map<ovdl::symbol<char>, FlatValue const*, symbol_hash> named_arguments; - ov_asm_argument::type_t ov_asm_type; + Asm::argument::type_t ov_asm_type; dryad::visit_tree( node, // @@ -353,10 +178,8 @@ void Codegen::generate_effect_from(scope_type type, Node* node) { // TODO: loop header } - // TODO: build arguments from named_arguments - arguments = lauf_asm_build_local( - _builder, lauf_asm_array_layout(LAUF_ASM_NATIVE_LAYOUT_OF(ov_asm_argument), named_arguments.size()) + *this, lauf_asm_array_layout(LAUF_ASM_NATIVE_LAYOUT_OF(Asm::argument), named_arguments.size()) ); std::size_t index = 0; @@ -374,9 +197,9 @@ void Codegen::generate_effect_from(scope_type type, Node* node) { is_arguments = false; } else if (auto yes_symbol = _parser.find_intern("yes"sv); yes_symbol && right->value() == yes_symbol) { // Build empty arguments - arguments = lauf_asm_build_local(_builder, lauf_asm_array_layout(lauf_asm_type_value.layout, 0)); + arguments = lauf_asm_build_local(*this, lauf_asm_array_layout(LAUF_ASM_NATIVE_LAYOUT_OF(Asm::argument), 0)); } else if (_parser.find_intern("no"sv) != right->value()) { - arguments = lauf_asm_build_local(_builder, lauf_asm_array_layout(lauf_asm_type_value.layout, 1)); + arguments = lauf_asm_build_local(*this, lauf_asm_array_layout(LAUF_ASM_NATIVE_LAYOUT_OF(Asm::argument), 1)); inst_store_ov_asm_key_null(arguments, 0); visitor(right); @@ -386,26 +209,26 @@ void Codegen::generate_effect_from(scope_type type, Node* node) { } // Load arguments address (vstack[2]) - lauf_asm_inst_local_addr(_builder, arguments); + lauf_asm_inst_local_addr(*this, arguments); // Load scope address in lauf (vstack[1]) - push_instruction_for_scope(current_scope.type, current_scope.symbol); + push_instruction_for_keyword_scope(scope_execution_type::Effect, current_scope.type, current_scope.symbol); // Create effect name literal (vstack[0]) - auto effect_name = lauf_asm_build_string_literal(_builder, left->value().c_str()); - lauf_asm_inst_global_addr(_builder, effect_name); + auto effect_name = lauf_asm_build_string_literal(*this, left->value().c_str()); + lauf_asm_inst_global_addr(*this, effect_name); // Consumes vstack[0], vstack[1], and vstack[2] - lauf_asm_inst_call_builtin(_builder, call_effect); + lauf_asm_inst_call_builtin(*this, call_effect); if (is_iterative) { // TODO: loop footer } }, [&](const FlatValue* value) { - using enum ov_asm_argument::type_t; + using enum Asm::argument::type_t; if (!is_arguments) { return; } - if (push_instruction_for_scope(current_scope.type, value->value())) { + if (push_instruction_for_keyword_scope(scope_execution_type::Effect, current_scope.type, value->value())) { ov_asm_type = scope; return; } @@ -413,14 +236,14 @@ void Codegen::generate_effect_from(scope_type type, Node* node) { auto view = value->value().view(); if (view[0] == '-') { if (std::int64_t value; std::from_chars(view.begin(), view.end(), value).ptr == view.end()) { - lauf_asm_inst_sint(_builder, value); + lauf_asm_inst_sint(*this, value); ov_asm_type = int_; return; } } if (std::uint64_t value; std::from_chars(view.begin(), view.end(), value).ptr == view.end()) { - lauf_asm_inst_uint(_builder, value); + lauf_asm_inst_uint(*this, value); ov_asm_type = uint; return; } @@ -429,15 +252,15 @@ void Codegen::generate_effect_from(scope_type type, Node* node) { bool success; auto value = fixed_point_t::parse(view, &success); if (success) { - lauf_asm_inst_sint(_builder, value.get_raw_value()); + lauf_asm_inst_sint(*this, value.get_raw_value()); ov_asm_type = fixed_point; return; } } // Create argument string literal - auto argument_str = lauf_asm_build_string_literal(_builder, value->value().c_str()); - lauf_asm_inst_global_addr(_builder, argument_str); + auto argument_str = lauf_asm_build_string_literal(*this, value->value().c_str()); + lauf_asm_inst_global_addr(*this, argument_str); ov_asm_type = cstring; // TODO: find/create and insert value here @@ -483,144 +306,78 @@ void Codegen::generate_condition_from(scope_type type, Node* node) { ); } -bool Codegen::push_instruction_for_scope(scope_type type, ovdl::symbol<char> scope_symbol) { - - auto is_scope = [&](std::string_view name) -> bool { - auto intern = _parser.find_intern(name); - return intern && intern == scope_symbol; - }; - - if (is_scope("this"sv)) { - inst_push_scope_this(); - return true; - } else if (is_scope("from"sv)) { - inst_push_scope_from(); - return true; - } else if (is_scope("cultural_union"sv)) { - DRYAD_PRECONDITION(std::has_single_bit(ovdl::detail::to_underlying(type))); - switch (type) { - case scope_type::Country: // - inst_push_get_country_cultural_union(); - return true; - case scope_type::State: // - inst_push_get_state_cultural_union(); - return true; - case scope_type::Province: // - DRYAD_ASSERT(false, "province scope does not support cultural_union scope"); - break; - case scope_type::Pop: // - inst_push_get_pop_cultural_union(); - return true; - default: return false; - } - } else { - DRYAD_PRECONDITION(std::has_single_bit(ovdl::detail::to_underlying(type))); - switch (type) { - case scope_type::Country: - if (is_scope("capital_scope"sv)) { - inst_push_get_country_capital(); - return true; - } else if (is_scope("overlord"sv)) { - inst_push_get_country_overlord(); - return true; - } else if (is_scope("sphere_owner"sv)) { - inst_push_get_country_sphere_owner(); - return true; - } else if (is_scope("random_country"sv)) { - inst_push_get_random_country(); - return true; - } else if (is_scope("random_owned"sv)) { - inst_push_get_random_owned(); - return true; - } else if (is_scope("random_pop"sv)) { - } - break; - case scope_type::State: break; - case scope_type::Province: - if (is_scope("controller"sv)) { - inst_push_get_province_controller(); - return true; - } else if (is_scope("owner"sv)) { - inst_push_get_province_owner(); - return true; - } else if (is_scope("state_scope"sv)) { - inst_push_get_province_state(); - return true; - } else if (is_scope("random_neighbor_province"sv)) { - inst_push_get_random_neighbor_province(); - return true; - } else if (is_scope("random_empty_neighbor_province"sv)) { - inst_push_get_random_empty_neighbor_province(); - return true; - } - break; - case scope_type::Pop: - if (is_scope("country"sv)) { - inst_push_get_pop_country(); - return true; - } else if (is_scope("location"sv)) { - inst_push_get_pop_location(); - return true; - } - break; - default: return false; - } +bool Codegen::push_instruction_for_keyword_scope( + scope_execution_type execution_type, scope_type type, ovdl::symbol<char> scope_symbol +) { + if (type >> get_scope_type_for(execution_type, scope_symbol)) { + lauf_asm_inst_uint(*this, _scope_references.size()); + _scope_references.push_back(get_scope_for(execution_type, type, scope_symbol)); + // TODO: push scope into _scope_references + lauf_asm_inst_call_builtin(*this, load_scope_ptr); } + return false; } -static constexpr lauf_asm_layout aggregate_layouts[] = { LAUF_ASM_NATIVE_LAYOUT_OF(ov_asm_argument::key), - LAUF_ASM_NATIVE_LAYOUT_OF(ov_asm_argument::type), - LAUF_ASM_NATIVE_LAYOUT_OF(ov_asm_argument::value) }; +OpenVic::Asm::scope_variant Codegen::get_scope_for( // + scope_execution_type execution_type, scope_type type, ovdl::symbol<char> scope_symbol +) const { + return {}; +} + +static constexpr lauf_asm_layout ov_asm_argument_layout[] = { LAUF_ASM_NATIVE_LAYOUT_OF(OpenVic::Asm::argument::key), + LAUF_ASM_NATIVE_LAYOUT_OF(OpenVic::Asm::argument::type), + LAUF_ASM_NATIVE_LAYOUT_OF(OpenVic::Asm::argument::value) }; bool Codegen::inst_store_ov_asm_key_null(lauf_asm_local* local, std::size_t index) { - lauf_asm_inst_null(_builder); + lauf_asm_inst_null(*this); // Start Load arguments // // vstack[1] - lauf_asm_inst_local_addr(_builder, local); + lauf_asm_inst_local_addr(*this, local); // vstack[0] - lauf_asm_inst_uint(_builder, index); + lauf_asm_inst_uint(*this, index); // Consumes vstack[0] = arguments_index, vstack[1] = argument_key_address, produces array address as // vstack[0] - lauf_asm_inst_array_element(_builder, lauf_asm_type_value.layout); + lauf_asm_inst_array_element(*this, lauf_asm_type_value.layout); // End Load arguments // - lauf_asm_inst_aggregate_member(_builder, 0, aggregate_layouts, 3); + lauf_asm_inst_aggregate_member(*this, 0, ov_asm_argument_layout, 3); // Consumes vstack[0] and vstack[1] - lauf_asm_inst_store_field(_builder, lauf_asm_type_value, 0); + lauf_asm_inst_store_field(*this, lauf_asm_type_value, 0); return true; } bool Codegen::inst_store_ov_asm_key(lauf_asm_local* local, std::size_t index, ovdl::symbol<char> key) { // Create key literal - auto argument_key = lauf_asm_build_string_literal(_builder, key.c_str()); - lauf_asm_inst_global_addr(_builder, argument_key); + auto argument_key = lauf_asm_build_string_literal(*this, key.c_str()); + lauf_asm_inst_global_addr(*this, argument_key); // Translate key literal to cstring - lauf_asm_inst_call_builtin(_builder, translate_address_to_string); + lauf_asm_inst_call_builtin(*this, translate_address_to_string); // Start Load arguments // // vstack[1] - lauf_asm_inst_local_addr(_builder, local); + lauf_asm_inst_local_addr(*this, local); // vstack[0] - lauf_asm_inst_uint(_builder, index); + lauf_asm_inst_uint(*this, index); // Consumes vstack[0] = arguments_index, vstack[1] = argument_key_address, produces array address as // vstack[0] - lauf_asm_inst_array_element(_builder, lauf_asm_type_value.layout); + lauf_asm_inst_array_element(*this, lauf_asm_type_value.layout); // End Load arguments // - lauf_asm_inst_aggregate_member(_builder, 0, aggregate_layouts, 3); + lauf_asm_inst_aggregate_member(*this, 0, ov_asm_argument_layout, 3); // Consumes vstack[0] and vstack[1] - lauf_asm_inst_store_field(_builder, lauf_asm_type_value, 0); + lauf_asm_inst_store_field(*this, lauf_asm_type_value, 0); return true; } bool Codegen::inst_store_ov_asm_value_from_vstack(lauf_asm_local* local, std::size_t index, std::uint8_t type) { - switch (ovdl::detail::from_underlying<ov_asm_argument::type_t>(type)) { - using enum ov_asm_argument::type_t; + switch (ovdl::detail::from_underlying<Asm::argument::type_t>(type)) { + using enum Asm::argument::type_t; case cstring: // Translate key literal to cstring - lauf_asm_inst_call_builtin(_builder, translate_address_to_string); - case scope: + lauf_asm_inst_call_builtin(*this, translate_address_to_string); case ptr: // Translate address to pointer - lauf_asm_inst_call_builtin(_builder, translate_address_to_pointer); + lauf_asm_inst_call_builtin(*this, translate_address_to_pointer); + case scope: + // Scope pointer is already native case uint: case int_: case fixed_point: @@ -630,32 +387,32 @@ bool Codegen::inst_store_ov_asm_value_from_vstack(lauf_asm_local* local, std::si // Start Load arguments // // vstack[1] - lauf_asm_inst_local_addr(_builder, local); + lauf_asm_inst_local_addr(*this, local); // vstack[0] - lauf_asm_inst_uint(_builder, index); + lauf_asm_inst_uint(*this, index); // Consumes vstack[0] = arguments_index, vstack[1] = argument_key_address, produces array address as // vstack[0] - lauf_asm_inst_array_element(_builder, lauf_asm_type_value.layout); + lauf_asm_inst_array_element(*this, lauf_asm_type_value.layout); // End Load arguments // - lauf_asm_inst_aggregate_member(_builder, 2, aggregate_layouts, 3); + lauf_asm_inst_aggregate_member(*this, 2, ov_asm_argument_layout, 3); // Consumes vstack[0] and vstack[1] - lauf_asm_inst_store_field(_builder, lauf_asm_type_value, 0); + lauf_asm_inst_store_field(*this, lauf_asm_type_value, 0); return true; } bool Codegen::inst_store_ov_asm_type(lauf_asm_local* local, std::size_t index, std::uint8_t type) { - lauf_asm_inst_uint(_builder, static_cast<lauf_uint>(type)); + lauf_asm_inst_uint(*this, static_cast<lauf_uint>(type)); // Start Load arguments // // vstack[1] - lauf_asm_inst_local_addr(_builder, local); + lauf_asm_inst_local_addr(*this, local); // vstack[0] - lauf_asm_inst_uint(_builder, index); + lauf_asm_inst_uint(*this, index); // Consumes vstack[0] = arguments_index, vstack[1] = argument_key_address, produces array address as // vstack[0] - lauf_asm_inst_array_element(_builder, lauf_asm_type_value.layout); + lauf_asm_inst_array_element(*this, lauf_asm_type_value.layout); // End Load arguments // - lauf_asm_inst_aggregate_member(_builder, 1, aggregate_layouts, 3); + lauf_asm_inst_aggregate_member(*this, 1, ov_asm_argument_layout, 3); // Consumes vstack[0] and vstack[1] - lauf_asm_inst_store_field(_builder, lauf_asm_type_value, 0); + lauf_asm_inst_store_field(*this, lauf_asm_type_value, 0); return true; } diff --git a/src/openvic-simulation/vm/Codegen.hpp b/src/openvic-simulation/vm/Codegen.hpp index c63ab9e..e7caee0 100644 --- a/src/openvic-simulation/vm/Codegen.hpp +++ b/src/openvic-simulation/vm/Codegen.hpp @@ -1,22 +1,28 @@ #pragma once +#include <vector> + #include <openvic-dataloader/detail/SymbolIntern.hpp> #include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp> #include <openvic-dataloader/v2script/Parser.hpp> #include "AsmBuilder.hpp" +#include "InstanceManager.hpp" #include "Module.hpp" #include "types/EnumBitfield.hpp" +#include "vm/Builtin.hpp" +#include "vm/VirtualMachine.hpp" #include <lauf/asm/builder.h> +#include <lauf/vm.h> namespace OpenVic::Vm { struct Codegen { Codegen( - ovdl::v2script::Parser const& parser, const char* module_name, + ovdl::v2script::Parser const& parser, InstanceManager* instance_manager, const char* module_name, lauf_asm_build_options options = lauf_asm_default_build_options ); - Codegen(ovdl::v2script::Parser const& parser, Module&& module, AsmBuilder&& builder); + Codegen(ovdl::v2script::Parser const& parser, InstanceManager* instance_manager, Module&& module, AsmBuilder&& builder); operator lauf_asm_module*() { return _module; @@ -50,6 +56,10 @@ namespace OpenVic::Vm { return _builder; } + OpenVicVirtualMachine create_virtual_machine() && { + return { _instance_manager, std::move(_scope_references) }; + } + lauf_asm_block* create_block(size_t input_count) { return lauf_asm_declare_block(_builder, input_count); } @@ -90,7 +100,13 @@ namespace OpenVic::Vm { bool inst_store_ov_asm_value_from_vstack(lauf_asm_local* local, std::size_t index, std::uint8_t type); bool inst_store_ov_asm_type(lauf_asm_local* local, std::size_t index, std::uint8_t type); - bool push_instruction_for_scope(scope_type type, ovdl::symbol<char> scope_symbol); + bool push_instruction_for_keyword_scope( + scope_execution_type execution_type, scope_type type, ovdl::symbol<char> scope_symbol + ); + + Asm::scope_variant get_scope_for( // + scope_execution_type execution_type, scope_type type, ovdl::symbol<char> scope_symbol + ) const; // Bytecode instructions // void inst_push_scope_this(); @@ -139,6 +155,7 @@ namespace OpenVic::Vm { void inst_push_get_trade_policy(const char* trade_policy_id); void inst_push_get_war_policy(const char* war_policy_id); + void inst_push_get_citizenship_policy(const char* citizenship_policy_id); void inst_push_get_issue(const char* issue_id); void inst_push_get_ideology(const char* ideology_id); @@ -176,6 +193,8 @@ namespace OpenVic::Vm { }; private: + std::vector<OpenVic::Asm::scope_variant> _scope_references; + InstanceManager* _instance_manager; Module _module; AsmBuilder _builder; ovdl::v2script::Parser const& _parser; diff --git a/src/openvic-simulation/vm/VirtualMachine.hpp b/src/openvic-simulation/vm/VirtualMachine.hpp index 4398f91..b92fb6c 100644 --- a/src/openvic-simulation/vm/VirtualMachine.hpp +++ b/src/openvic-simulation/vm/VirtualMachine.hpp @@ -1,7 +1,11 @@ #pragma once +#include <vector> + +#include "InstanceManager.hpp" #include "RuntimeProcess.hpp" #include "Utility.hpp" +#include "vm/Builtin.hpp" #include <lauf/vm.h> namespace OpenVic::Vm { @@ -23,4 +27,24 @@ namespace OpenVic::Vm { return RuntimeProcess(lauf_vm_start_process(*this, program)); } }; + + struct OpenVicVirtualMachine : VirtualMachine { + using VirtualMachine::VirtualMachine; + using VirtualMachine::operator=; + + OpenVicVirtualMachine( + InstanceManager* instance_manager, std::vector<Asm::scope_variant>&& scope_references, + lauf_vm_options options = lauf_default_vm_options + ) + : VirtualMachine([&] { + options.user_data = &user_data; + return options; + }()) { + user_data.scope_references = std::move(scope_references); + user_data.instance_manager = instance_manager; + } + + private: + VmUserData user_data; + }; } |