From 1bbe36737baa09e219cb01d3b81315a0e15ac842 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Thu, 23 May 2024 18:20:35 -0700 Subject: [PATCH 01/10] feat: implement new assoc api --- MODULE.bazel | 2 +- parse-resolver-runtime/BUILD.bazel | 2 +- parse-resolver-runtime/assoc.cc | 223 +++++++++++++++++++++++++++++ 3 files changed, 225 insertions(+), 2 deletions(-) create mode 100644 parse-resolver-runtime/assoc.cc diff --git a/MODULE.bazel b/MODULE.bazel index 8ad4a01..c8ab01e 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -7,7 +7,7 @@ module( bazel_dep(name = "rules_cc", version = "0.0.9") bazel_dep(name = "bazel_skylib", version = "1.5.0") bazel_dep(name = "magic_enum", version = "0.9.3") -bazel_dep(name = "ecsact_runtime", version = "0.6.1") +bazel_dep(name = "ecsact_runtime", version = "0.6.3") bazel_dep(name = "ecsact_parse", version = "0.4.0") bazel_dep(name = "toolchains_llvm", version = "1.0.0", dev_dependency = True) diff --git a/parse-resolver-runtime/BUILD.bazel b/parse-resolver-runtime/BUILD.bazel index f8ff60f..1ec4b5c 100644 --- a/parse-resolver-runtime/BUILD.bazel +++ b/parse-resolver-runtime/BUILD.bazel @@ -5,7 +5,7 @@ package(default_visibility = ["//:__subpackages__"]) cc_library( name = "parse-resolver-runtime", - srcs = ["parse-resolver-runtime.cc"], + srcs = ["parse-resolver-runtime.cc", "assoc.cc"], copts = copts, defines = [ "ECSACT_DYNAMIC_API=\"\"", diff --git a/parse-resolver-runtime/assoc.cc b/parse-resolver-runtime/assoc.cc new file mode 100644 index 0000000..a87d7d0 --- /dev/null +++ b/parse-resolver-runtime/assoc.cc @@ -0,0 +1,223 @@ +#include "ecsact/runtime/meta.h" + +#include +#include +#include +#include +#include + +static auto gen_next_assoc_id() -> ecsact_system_assoc_id { + static ecsact_system_assoc_id next_assoc_id = {}; + ecsact_system_assoc_id result = next_assoc_id; + + reinterpret_cast&>( + next_assoc_id + ) += 1; + + return result; +} + +struct assoc_info { + using cap_comp_list_t = + std::vector>; + + ecsact_system_assoc_id id; + ecsact_component_like_id comp_id; + std::vector assoc_fields; + + cap_comp_list_t caps; +}; + +using system_assoc_map_info_t = + std::unordered_map>; + +static system_assoc_map_info_t system_assoc_info{}; + +static auto get_system_assoc_list( // + ecsact_system_like_id system_id +) -> std::vector* { + auto itr = system_assoc_info.find(system_id); + if(itr != system_assoc_info.end()) { + return &itr->second; + } + + return nullptr; +} + +static auto get_assoc_info( // + ecsact_system_like_id system_id, + ecsact_system_assoc_id assoc_id +) -> assoc_info* { + auto list = get_system_assoc_list(system_id); + if(!list) { + return nullptr; + } + + auto itr = std::find_if( // + list->begin(), + list->end(), + [=](auto item) -> bool { return item.id == assoc_id; } + ); + + if(itr == list->end()) { + return nullptr; + } + + return &(*itr); +} + +ecsact_system_assoc_id ecsact_add_system_assoc( // + ecsact_system_like_id system_id +) { + auto itr = system_assoc_info.find(system_id); + if(itr == system_assoc_info.end()) { + itr = system_assoc_info.insert(system_assoc_info.end(), {system_id, {}}); + } + + auto& info = itr->second.emplace_back(assoc_info{}); + info.id = gen_next_assoc_id(); + return info.id; +} + +void ecsact_remove_system_assoc( // + ecsact_system_like_id system_id, + ecsact_system_assoc_id assoc_id +) { + auto list = get_system_assoc_list(system_id); + if(!list) { + // No associations. Why did you try to remove? User error. + return; + } + + auto itr = std::find_if( // + list->begin(), + list->end(), + [=](auto item) -> bool { return item.id == assoc_id; } + ); + + if(itr == list->end()) { + // Unknown association id. User error. + return; + } + + list->erase(itr); +} + +int32_t ecsact_meta_system_assoc_count( // + ecsact_system_like_id system_id +) { + auto list = get_system_assoc_list(system_id); + if(list) { + return list->size(); + } + + return 0; +} + +int32_t ecsact_meta_system_assoc_ids( + ecsact_system_like_id system_id, + int32_t max_assoc_count, + ecsact_system_assoc_id* out_assoc_ids, + int32_t* out_assoc_count +) { + auto list = get_system_assoc_list(system_id); + if(!list) { + if(out_assoc_count) { + *out_assoc_count = 0; + } + return 0; + } + + if(out_assoc_count) { + *out_assoc_count = list->size(); + } + + for(int32_t i = 0; max_assoc_count > i; ++i) { + if(i >= list->size()) { + break; + } + auto& assoc = list->at(i); + out_assoc_ids[i] = assoc.id; + } + + return 0; +} + +int32_t ecsact_meta_system_assoc_fields_count( + ecsact_system_like_id system_id, + ecsact_system_assoc_id assoc_id +) { + auto info = get_assoc_info(system_id, assoc_id); + if(!info) { + return 0; + } + + return static_cast(info->assoc_fields.size()); +} + +int32_t ecsact_meta_system_assoc_fields( + ecsact_system_like_id system_id, + ecsact_system_assoc_id assoc_id, + int32_t max_fields_count, + ecsact_field_id* out_fields, + int32_t* out_fields_count +) { + auto info = get_assoc_info(system_id, assoc_id); + if(!info) { + if(out_fields_count) { + *out_fields_count = 0; + } + return 0; + } + + if(out_fields_count) { + *out_fields_count = info->assoc_fields.size(); + } + + for(int32_t i = 0; max_fields_count > i; ++i) { + if(i >= info->assoc_fields.size()) { + break; + } + out_fields[i] = info->assoc_fields[i]; + } + + return 0; +} + +int32_t ecsact_meta_system_assoc_capabilities_count( + ecsact_system_like_id system_id, + ecsact_system_assoc_id assoc_id +) { + auto info = get_assoc_info(system_id, assoc_id); + if(!info) { + return 0; + } + + return info->caps.size(); +} + +void ecsact_meta_system_assoc_capabilities( + ecsact_system_like_id system_id, + ecsact_system_assoc_id assoc_id, + int32_t max_capabilities_count, + ecsact_component_like_id* out_capability_component_ids, + ecsact_system_capability* out_capabilities, + int32_t* out_capabilities_count +) { + auto info = get_assoc_info(system_id, assoc_id); + if(!info) { + if(out_capabilities_count) { + *out_capabilities_count = 0; + } + return; + } + + for(int32_t i = 0; max_capabilities_count > i; ++i) { + if(i >= info->caps.size()) { + break; + } + + out_capability_component_ids[i] = info->caps[i].first; + out_capabilities[i] = info->caps[i].second; + } +} From a29d0fa50ea3b5d53409b07e2cd2fd6c4e4ea0fe Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Thu, 23 May 2024 18:25:41 -0700 Subject: [PATCH 02/10] feat: optional component like id --- parse-resolver-runtime/assoc.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parse-resolver-runtime/assoc.cc b/parse-resolver-runtime/assoc.cc index a87d7d0..5b2d1b9 100644 --- a/parse-resolver-runtime/assoc.cc +++ b/parse-resolver-runtime/assoc.cc @@ -21,9 +21,9 @@ struct assoc_info { using cap_comp_list_t = std::vector>; - ecsact_system_assoc_id id; - ecsact_component_like_id comp_id; - std::vector assoc_fields; + ecsact_system_assoc_id id; + std::optional comp_id; + std::vector assoc_fields; cap_comp_list_t caps; }; From 901cfce1aa5b6463feec26ab5f2eaf8acbd2fc2c Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Fri, 24 May 2024 16:21:02 -0700 Subject: [PATCH 03/10] chore: wip new assoc api --- BUILD.bazel | 1 + MODULE.bazel | 7 +- ecsact/interpret/eval.cc | 251 ++++++++---------- ecsact/interpret/eval.h | 7 +- ecsact/interpret/eval_error.h | 3 + parse-resolver-runtime/BUILD.bazel | 2 +- parse-resolver-runtime/assoc.cc | 163 +++++++++--- parse-resolver-runtime/ids.cc | 16 ++ parse-resolver-runtime/ids.hh | 23 ++ parse-resolver-runtime/lifecycle.cc | 121 +++++++++ parse-resolver-runtime/lifecycle.hh | 60 +++++ .../parse-resolver-runtime.cc | 129 ++------- test/MODULE.bazel | 9 +- test/field_indexing.cc | 65 ++--- test/field_indexing.ecsact | 24 +- test/test_lib.hh | 42 +++ 16 files changed, 582 insertions(+), 341 deletions(-) create mode 100644 parse-resolver-runtime/ids.cc create mode 100644 parse-resolver-runtime/ids.hh create mode 100644 parse-resolver-runtime/lifecycle.cc create mode 100644 parse-resolver-runtime/lifecycle.hh diff --git a/BUILD.bazel b/BUILD.bazel index 81fcd24..b33d951 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -18,6 +18,7 @@ cc_library( deps = [ ":ecsact_interpret_detail", "//parse-resolver-runtime", + "@ecsact_runtime//:common", "@ecsact_parse", ], ) diff --git a/MODULE.bazel b/MODULE.bazel index c8ab01e..2e38443 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -8,7 +8,12 @@ bazel_dep(name = "rules_cc", version = "0.0.9") bazel_dep(name = "bazel_skylib", version = "1.5.0") bazel_dep(name = "magic_enum", version = "0.9.3") bazel_dep(name = "ecsact_runtime", version = "0.6.3") -bazel_dep(name = "ecsact_parse", version = "0.4.0") +bazel_dep(name = "ecsact_parse", version = "0.5.0") + +local_path_override( + module_name = "ecsact_runtime", + path = "../ecsact_runtime", +) bazel_dep(name = "toolchains_llvm", version = "1.0.0", dev_dependency = True) bazel_dep(name = "hedron_compile_commands", dev_dependency = True) diff --git a/ecsact/interpret/eval.cc b/ecsact/interpret/eval.cc index 27beffe..fccaf54 100644 --- a/ecsact/interpret/eval.cc +++ b/ecsact/interpret/eval.cc @@ -1,6 +1,5 @@ #include "ecsact/interpret/eval.h" -#include #include #include #include @@ -8,16 +7,15 @@ #include #include #include -#include #include #include -#include "magic_enum.hpp" -#include "ecsact/parse.h" +#include "ecsact/parse/status.h" #include "ecsact/runtime/dynamic.h" #include "ecsact/runtime/meta.hh" #include "ecsact/runtime/meta.h" #include "./detail/file_eval_error.hh" +#include "eval_error.h" using namespace std::string_literals; using namespace std::string_view_literals; @@ -1056,6 +1054,53 @@ static ecsact_eval_error eval_entity_field_statement( ); } +static auto eval_system_with_statement_data_common( + ecsact_system_like_id sys_like_id, + ecsact_component_like_id comp_like_id, + std::span fields +) -> ecsact_eval_error { + auto with_field_ids = std::vector{}; + for(int i = 0; fields.size() > i; ++i) { + auto assoc_field_name = + std::string_view{fields[i].data, static_cast(fields[i].length)}; + + auto assoc_field_id = std::optional{}; + + for(auto field_id : ecsact::meta::get_field_ids(comp_like_id)) { + std::string field_name = ecsact_meta_field_name( + ecsact_id_cast(comp_like_id), + field_id + ); + if(assoc_field_name == field_name) { + assoc_field_id = field_id; + break; + } + } + + if(!assoc_field_id) { + return ecsact_eval_error{ + .code = ECSACT_EVAL_ERR_UNKNOWN_FIELD_NAME, + .relevant_content = fields[i], + }; + } + } + + if(with_field_ids.empty()) { + return ecsact_eval_error{ + .code = ECSACT_EVAL_ERR_UNEXPECTED_STATEMENT, + .relevant_content = {}, + }; + } + + auto assoc_id = ecsact_add_system_assoc(sys_like_id, comp_like_id); + + for(auto assoc_field_id : with_field_ids) { + ecsact_add_system_assoc_field(sys_like_id, assoc_id, assoc_field_id); + } + + return {}; +} + static ecsact_eval_error eval_system_component_statement( ecsact_package_id package_id, std::span& context_stack, @@ -1080,20 +1125,42 @@ static ecsact_eval_error eval_system_component_statement( return *err; } - std::optional sys_like_id{}; - std::optional assoc_comp{}; - std::optional assoc_comp_field{}; + auto& statement_data = statement.data.system_component_statement; + auto sys_like_id = std::optional{}; + auto assoc_id = std::optional{}; + + std::string comp_like_name( + statement_data.component_name.data, + statement_data.component_name.length + ); + + auto comp_like_id = + find_by_name(package_id, comp_like_name); + + if(!comp_like_id) { + return ecsact_eval_error{ + .code = ECSACT_EVAL_ERR_UNKNOWN_COMPONENT_LIKE_TYPE, + .relevant_content = statement_data.component_name, + }; + } // See expect_context above for options here switch(context->type) { + // system Example { + // readwrite ExampleComponent with blah <-- we are here + // } case ECSACT_STATEMENT_SYSTEM: - case ECSACT_STATEMENT_ACTION: + case ECSACT_STATEMENT_ACTION: { sys_like_id = find_by_statement(package_id, *context); break; + } + // system Example { + // readwrite ExampleComponent with blah { + // readwrite ExampleComponent <-- we are here + // } + // } case ECSACT_STATEMENT_SYSTEM_COMPONENT: { - auto& data = context->data.system_component_statement; - if(context_stack.size() < 2) { return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, @@ -1105,40 +1172,13 @@ static ecsact_eval_error eval_system_component_statement( context_stack[context_stack.size() - 2] ); - std::string comp_like_name( - data.component_name.data, - data.component_name.length - ); - - assoc_comp = - find_by_name(package_id, comp_like_name); - if(!assoc_comp) { + if(statement_data.with_field_name_list_count > 0) { return ecsact_eval_error{ - .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, - .relevant_content = {}, + .code = ECSACT_EVAL_ERR_NESTED_ASSOC, + .relevant_content = statement_data.with_field_name_list[0], }; } - if(data.with_entity_field_name.length == 0) { - return ecsact_eval_error{ - .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, - .relevant_content = data.component_name, - }; - } - assoc_comp_field = find_field_by_name( - ecsact_id_cast(*assoc_comp), - std::string_view( - data.with_entity_field_name.data, - data.with_entity_field_name.length - ) - ); - - if(!assoc_comp_field) { - return ecsact_eval_error{ - .code = ECSACT_EVAL_ERR_UNKNOWN_FIELD_NAME, - .relevant_content = data.with_entity_field_name, - }; - } break; } default: @@ -1162,84 +1202,43 @@ static ecsact_eval_error eval_system_component_statement( }; } - auto& data = statement.data.system_component_statement; - - std::string comp_like_name( - data.component_name.data, - data.component_name.length - ); - - auto comp_like_id = - find_by_name(package_id, comp_like_name); - - if(!comp_like_id) { - return ecsact_eval_error{ - .code = ECSACT_EVAL_ERR_UNKNOWN_COMPONENT_LIKE_TYPE, - .relevant_content = data.component_name, - }; - } - - if(assoc_comp) { - auto assoc_caps = ecsact::meta::system_association_capabilities( + if(statement_data.with_field_name_list_count > 0) { + auto status = eval_system_with_statement_data_common( *sys_like_id, - *assoc_comp, - *assoc_comp_field - ); - for(auto& entry : assoc_caps) { - if(entry.first == *comp_like_id) { - return ecsact_eval_error{ - .code = ECSACT_EVAL_ERR_MULTIPLE_CAPABILITIES_SAME_COMPONENT_LIKE, - .relevant_content = data.component_name, - }; - } - } - } else { - for(auto& entry : ecsact::meta::system_capabilities(*sys_like_id)) { - if(entry.first == *comp_like_id) { - return ecsact_eval_error{ - .code = ECSACT_EVAL_ERR_MULTIPLE_CAPABILITIES_SAME_COMPONENT_LIKE, - .relevant_content = data.component_name, - }; + *comp_like_id, + std::span{ + std::data(statement_data.with_field_name_list), + static_cast(statement_data.with_field_name_list_count) } - } - } - - std::optional entity_field_id{}; - if(data.with_entity_field_name.length > 0) { - std::string entity_field_name( - data.with_entity_field_name.data, - data.with_entity_field_name.length ); - for(auto field_id : ecsact::meta::get_field_ids(*comp_like_id)) { - std::string field_name = ecsact_meta_field_name( - ecsact_id_cast(*comp_like_id), - field_id - ); - if(entity_field_name == field_name) { - entity_field_id = field_id; - break; - } + if(status.code != ECSACT_EVAL_OK) { + return status; } + } - if(!entity_field_id) { + for(auto& entry : ecsact::meta::system_capabilities(*sys_like_id)) { + if(entry.first == *comp_like_id) { return ecsact_eval_error{ - .code = ECSACT_EVAL_ERR_FIELD_NAME_ALREADY_EXISTS, - .relevant_content = data.with_entity_field_name, + .code = ECSACT_EVAL_ERR_MULTIPLE_CAPABILITIES_SAME_COMPONENT_LIKE, + .relevant_content = statement_data.component_name, }; } } - if(assoc_comp) { - ecsact_set_system_association_capability( + if(assoc_id) { + ecsact_set_system_assoc_capability( *sys_like_id, - *assoc_comp, - *assoc_comp_field, + *assoc_id, *comp_like_id, - data.capability + statement_data.capability ); } else { - ecsact_set_system_capability(*sys_like_id, *comp_like_id, data.capability); + ecsact_set_system_capability( + *sys_like_id, + *comp_like_id, + statement_data.capability + ); } return {}; @@ -1289,7 +1288,7 @@ static ecsact_eval_error eval_system_generates_statement( return {}; } -static ecsact_eval_error eval_system_with_entity_statement( +static ecsact_eval_error eval_system_with_statement( ecsact_package_id package_id, std::span& context_stack, const ecsact_statement& statement @@ -1305,8 +1304,10 @@ static ecsact_eval_error eval_system_with_entity_statement( expect_context(context_stack, {ECSACT_STATEMENT_SYSTEM_COMPONENT}); if(err.code != ECSACT_EVAL_OK) { - err.relevant_content = - statement.data.system_with_entity_statement.with_entity_field_name; + if(statement.data.system_with_statement.with_field_name_list_count > 0) { + err.relevant_content = + statement.data.system_with_statement.with_field_name_list[0]; + } return err; } @@ -1341,33 +1342,16 @@ static ecsact_eval_error eval_system_with_entity_statement( }; } - auto& data = statement.data.system_with_entity_statement; + auto& data = statement.data.system_with_statement; - std::string entity_field_name( - data.with_entity_field_name.data, - data.with_entity_field_name.length - ); - - auto entity_field_id = std::optional{}; - for(auto field_id : ecsact::meta::get_field_ids(*comp_like_id)) { - std::string field_name = ecsact_meta_field_name( - ecsact_id_cast(*comp_like_id), - field_id - ); - if(entity_field_name == field_name) { - entity_field_id = field_id; - break; + return eval_system_with_statement_data_common( + *sys_like_id, + *comp_like_id, + std::span{ + std::data(data.with_field_name_list), + static_cast(data.with_field_name_list_count) } - } - - if(!entity_field_id) { - return ecsact_eval_error{ - .code = ECSACT_EVAL_ERR_FIELD_NAME_ALREADY_EXISTS, - .relevant_content = data.with_entity_field_name, - }; - } - - return {}; + ); } static auto get_notify_setting_from_string( // @@ -1709,8 +1693,8 @@ ecsact_eval_error ecsact_eval_statement( context_statements, statement ); - case ECSACT_STATEMENT_SYSTEM_WITH_ENTITY: - return eval_system_with_entity_statement( + case ECSACT_STATEMENT_SYSTEM_WITH: + return eval_system_with_statement( package_id, context_statements, statement @@ -1763,7 +1747,6 @@ ecsact_package_id ecsact_eval_package_statement( } void ecsact_eval_reset() { - // eval_pkgs.clear(); } void ecsact::detail::check_file_eval_error( diff --git a/ecsact/interpret/eval.h b/ecsact/interpret/eval.h index 51589c7..2f14fe5 100644 --- a/ecsact/interpret/eval.h +++ b/ecsact/interpret/eval.h @@ -2,7 +2,8 @@ #define ECSACT_INTERPRET_EVAL_H #include -#include "ecsact/parse.h" +#include "ecsact/parse/statements.h" +#include "ecsact/runtime/common.h" #include "ecsact/interpret/eval_error.h" typedef struct ecsact_eval_error { @@ -31,9 +32,7 @@ ecsact_eval_error ecsact_eval_statement( const ecsact_statement* statement_stack ); -/** - * @deprecated - */ +ECSACT_DEPRECATED("uneeded since interpreter does not hold state") void ecsact_eval_reset(); #endif // ECSACT_INTERPRET_EVAL_H diff --git a/ecsact/interpret/eval_error.h b/ecsact/interpret/eval_error.h index c277c41..07e2704 100644 --- a/ecsact/interpret/eval_error.h +++ b/ecsact/interpret/eval_error.h @@ -78,6 +78,9 @@ typedef enum ecsact_eval_error_code { /// Field type matches a user field and a field index name ECSACT_EVAL_ERR_AMBIGUOUS_FIELD_TYPE, + /// Nested association is not allowed + ECSACT_EVAL_ERR_NESTED_ASSOC, + /// Internal error. Should not happen and is an indiciation of a bug. ECSACT_EVAL_ERR_INTERNAL = 999, diff --git a/parse-resolver-runtime/BUILD.bazel b/parse-resolver-runtime/BUILD.bazel index 1ec4b5c..d548e61 100644 --- a/parse-resolver-runtime/BUILD.bazel +++ b/parse-resolver-runtime/BUILD.bazel @@ -5,7 +5,7 @@ package(default_visibility = ["//:__subpackages__"]) cc_library( name = "parse-resolver-runtime", - srcs = ["parse-resolver-runtime.cc", "assoc.cc"], + srcs = glob(["*.cc", "*.hh"]), copts = copts, defines = [ "ECSACT_DYNAMIC_API=\"\"", diff --git a/parse-resolver-runtime/assoc.cc b/parse-resolver-runtime/assoc.cc index 5b2d1b9..ee1bfc5 100644 --- a/parse-resolver-runtime/assoc.cc +++ b/parse-resolver-runtime/assoc.cc @@ -1,41 +1,44 @@ #include "ecsact/runtime/meta.h" +#include "ecsact/runtime/dynamic.h" -#include #include #include #include #include +#include +#include "parse-resolver-runtime/ids.hh" +#include "parse-resolver-runtime/lifecycle.hh" -static auto gen_next_assoc_id() -> ecsact_system_assoc_id { - static ecsact_system_assoc_id next_assoc_id = {}; - ecsact_system_assoc_id result = next_assoc_id; - - reinterpret_cast&>( - next_assoc_id - ) += 1; - - return result; -} +using ecsact::interpret::details::event_ref; +using ecsact::interpret::details::gen_next_id; +using ecsact::interpret::details::on_destroy; struct assoc_info { using cap_comp_list_t = std::vector>; - ecsact_system_assoc_id id; - std::optional comp_id; - std::vector assoc_fields; + ecsact_system_assoc_id id; + ecsact_component_like_id comp_id; + std::vector assoc_fields; cap_comp_list_t caps; + + std::vector event_refs; + + assoc_info() = default; + assoc_info(assoc_info&&) = default; + ~assoc_info() = default; }; -using system_assoc_map_info_t = - std::unordered_map>; +using system_assoc_map_info_t = std::unordered_map< + ecsact_system_like_id, + std::vector>>; static system_assoc_map_info_t system_assoc_info{}; static auto get_system_assoc_list( // ecsact_system_like_id system_id -) -> std::vector* { +) -> std::vector>* { auto itr = system_assoc_info.find(system_id); if(itr != system_assoc_info.end()) { return &itr->second; @@ -47,36 +50,49 @@ static auto get_system_assoc_list( // static auto get_assoc_info( // ecsact_system_like_id system_id, ecsact_system_assoc_id assoc_id -) -> assoc_info* { +) -> std::shared_ptr { auto list = get_system_assoc_list(system_id); if(!list) { - return nullptr; + return {}; } auto itr = std::find_if( // list->begin(), list->end(), - [=](auto item) -> bool { return item.id == assoc_id; } + [=](const auto& item) -> bool { return item->id == assoc_id; } ); if(itr == list->end()) { - return nullptr; + return {}; } - return &(*itr); + return *itr; } ecsact_system_assoc_id ecsact_add_system_assoc( // - ecsact_system_like_id system_id + ecsact_system_like_id system_id, + ecsact_component_like_id component_id ) { auto itr = system_assoc_info.find(system_id); if(itr == system_assoc_info.end()) { itr = system_assoc_info.insert(system_assoc_info.end(), {system_id, {}}); } - auto& info = itr->second.emplace_back(assoc_info{}); - info.id = gen_next_assoc_id(); - return info.id; + auto& info = itr->second.emplace_back(std::make_shared()); + info->id = gen_next_id(); + info->comp_id = component_id; + + info->event_refs + .emplace_back(on_destroy(system_id, [system_id, assoc_id = info->id]() { + ecsact_remove_system_assoc(system_id, assoc_id); + })); + + info->event_refs + .emplace_back(on_destroy(component_id, [system_id, assoc_id = info->id]() { + ecsact_remove_system_assoc(system_id, assoc_id); + })); + + return info->id; } void ecsact_remove_system_assoc( // @@ -92,7 +108,7 @@ void ecsact_remove_system_assoc( // auto itr = std::find_if( // list->begin(), list->end(), - [=](auto item) -> bool { return item.id == assoc_id; } + [=](const auto& item) -> bool { return item->id == assoc_id; } ); if(itr == list->end()) { @@ -103,6 +119,85 @@ void ecsact_remove_system_assoc( // list->erase(itr); } +void ecsact_add_system_assoc_field( + ecsact_system_like_id system_id, + ecsact_system_assoc_id assoc_id, + ecsact_field_id field_id +) { + auto info = get_assoc_info(system_id, assoc_id); + if(!info) { + return; + } + + auto itr = std::find( // + info->assoc_fields.begin(), + info->assoc_fields.end(), + field_id + ); + + if(itr != info->assoc_fields.end()) { + // Field already added. User error. + return; + } + + info->assoc_fields.push_back(field_id); +} + +void ecsact_remove_system_assoc_field( + ecsact_system_like_id system_id, + ecsact_system_assoc_id assoc_id, + ecsact_field_id field_id +) { + auto info = get_assoc_info(system_id, assoc_id); + if(!info) { + return; + } + + auto itr = std::find( // + info->assoc_fields.begin(), + info->assoc_fields.end(), + field_id + ); + + if(itr == info->assoc_fields.end()) { + // Field is already not associated. User error. + return; + } + + info->assoc_fields.erase(itr); +} + +void ecsact_set_system_assoc_capability( + ecsact_system_like_id system_id, + ecsact_system_assoc_id assoc_id, + ecsact_component_like_id comp_id, + ecsact_system_capability cap +) { + auto info = get_assoc_info(system_id, assoc_id); + if(!info) { + return; + } + + auto itr = std::find_if( + info->caps.begin(), + info->caps.end(), + [&](const auto& entry) -> bool { return entry.first == comp_id; } + ); + + if(cap == ECSACT_SYS_CAP_NONE) { + if(itr != info->caps.end()) { + info->caps.erase(itr); + } + return; + } + + if(itr == info->caps.end()) { + info->caps.emplace_back(comp_id, cap); + } else { + itr->second = cap; + } +} + int32_t ecsact_meta_system_assoc_count( // ecsact_system_like_id system_id ) { @@ -114,7 +209,7 @@ int32_t ecsact_meta_system_assoc_count( // return 0; } -int32_t ecsact_meta_system_assoc_ids( +void ecsact_meta_system_assoc_ids( ecsact_system_like_id system_id, int32_t max_assoc_count, ecsact_system_assoc_id* out_assoc_ids, @@ -125,7 +220,7 @@ int32_t ecsact_meta_system_assoc_ids( if(out_assoc_count) { *out_assoc_count = 0; } - return 0; + return; } if(out_assoc_count) { @@ -137,10 +232,8 @@ int32_t ecsact_meta_system_assoc_ids( break; } auto& assoc = list->at(i); - out_assoc_ids[i] = assoc.id; + out_assoc_ids[i] = assoc->id; } - - return 0; } int32_t ecsact_meta_system_assoc_fields_count( @@ -155,7 +248,7 @@ int32_t ecsact_meta_system_assoc_fields_count( return static_cast(info->assoc_fields.size()); } -int32_t ecsact_meta_system_assoc_fields( +void ecsact_meta_system_assoc_fields( ecsact_system_like_id system_id, ecsact_system_assoc_id assoc_id, int32_t max_fields_count, @@ -167,7 +260,7 @@ int32_t ecsact_meta_system_assoc_fields( if(out_fields_count) { *out_fields_count = 0; } - return 0; + return; } if(out_fields_count) { @@ -180,8 +273,6 @@ int32_t ecsact_meta_system_assoc_fields( } out_fields[i] = info->assoc_fields[i]; } - - return 0; } int32_t ecsact_meta_system_assoc_capabilities_count( diff --git a/parse-resolver-runtime/ids.cc b/parse-resolver-runtime/ids.cc new file mode 100644 index 0000000..e5237e5 --- /dev/null +++ b/parse-resolver-runtime/ids.cc @@ -0,0 +1,16 @@ +#include "parse-resolver-runtime/ids.hh" + +#include +#include + +static std::atomic_int32_t last_id = 0; + +auto ecsact::interpret::details::gen_next_id_() -> int32_t { + // Getting here would be crazy and if we were to do anything about it we'd + // have to implement an "ID recycling" mechanism which I think is overkill. + if(last_id == std::numeric_limits::max()) { + throw std::logic_error{"Max id count reached"}; + } + + return last_id++; +} diff --git a/parse-resolver-runtime/ids.hh b/parse-resolver-runtime/ids.hh new file mode 100644 index 0000000..ba58460 --- /dev/null +++ b/parse-resolver-runtime/ids.hh @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +namespace ecsact::interpret::details { + +/** + * @NOTE: Don't use this. Use gen_next_id() instead. + */ +auto gen_next_id_() -> int32_t; + +/** + * Simple ID generation tool + */ +template +// light restriction on ID type. All ecsact IDs are opaque enums. + requires(std::is_enum_v) +auto gen_next_id() -> ID { + return static_cast(gen_next_id_()); +} + +} // namespace ecsact::interpret::details diff --git a/parse-resolver-runtime/lifecycle.cc b/parse-resolver-runtime/lifecycle.cc new file mode 100644 index 0000000..e03f092 --- /dev/null +++ b/parse-resolver-runtime/lifecycle.cc @@ -0,0 +1,121 @@ +#include "parse-resolver-runtime/lifecycle.hh" + +#include +#include "ecsact/runtime/common.h" + +using ecsact::interpret::details::castable_destroyable_ids_t; +using ecsact::interpret::details::destroyable_id_t; +using ecsact::interpret::details::event_ref_id; + +struct lifecycle_calback_info { + event_ref_id last_event_ref_id = {}; + std::unordered_map callback_id; + std::unordered_map> callbacks; + + auto gen_next_id() -> event_ref_id { + using storage_t = std::underlying_type_t; + reinterpret_cast(last_event_ref_id) += 1; + return last_event_ref_id; + } +}; + +static std::array< // + lifecycle_calback_info, + std::variant_size_v> + lifecycle_info = {}; + +static auto destroyable_id_as_int(castable_destroyable_ids_t id) -> int { + return std::visit([](auto id) { return static_cast(id); }, id); +} + +static auto destroyable_id_as_int(destroyable_id_t id) -> int { + return std::visit([](auto id) { return static_cast(id); }, id); +} + +static auto callback_indicies(destroyable_id_t id) -> std::vector { + auto result = std::vector{}; + result.emplace_back(static_cast(id.index())); + + auto add_castable_id = [&](T v) -> void { + result.emplace_back( // + static_cast(castable_destroyable_ids_t{v}.index()) + ); + }; + + std::visit( + [&](T id) { + if constexpr(ecsact_id_castable()) { + add_castable_id(ecsact_component_like_id{}); + } + if constexpr(ecsact_id_castable()) { + add_castable_id(ecsact_composite_id{}); + } + if constexpr(ecsact_id_castable()) { + add_castable_id(ecsact_system_like_id{}); + } + if constexpr(ecsact_id_castable()) { + add_castable_id(ecsact_decl_id{}); + } + }, + id + ); + + return result; +} + +ecsact::interpret::details::event_ref::event_ref() = default; + +ecsact::interpret::details::event_ref::event_ref(event_ref&& other) { + id_ = other.id_; + other.id_ = {}; +} + +ecsact::interpret::details::event_ref::~event_ref() { + clear(); +} + +auto ecsact::interpret::details::event_ref::clear() -> void { + if(id_ == event_ref_id{}) { + return; + } + + auto& info = lifecycle_info[destroyable_index_]; + info.callbacks.erase(id_); + id_ = {}; +} + +auto ecsact::interpret::details::on_destroy( // + castable_destroyable_ids_t id, + std::function callback +) -> event_ref { + auto& info = lifecycle_info[static_cast(id.index())]; + + auto ref = event_ref{}; + ref.destroyable_index_ = static_cast(id.index()); + ref.id_ = info.gen_next_id(); + info.callbacks[ref.id_] = callback; + info.callback_id[ref.id_] = destroyable_id_as_int(id); + return ref; +} + +auto ecsact::interpret::details::trigger_on_destroy( // + destroyable_id_t id +) -> void { + for(auto index : callback_indicies(id)) { + auto& info = lifecycle_info[index]; + for(auto itr = info.callback_id.begin(); itr != info.callback_id.end();) { + auto& event_ref = itr->first; + auto callback_id = itr->second; + if(callback_id == destroyable_id_as_int(id)) { + auto callbacks_itr = info.callbacks.find(event_ref); + if(callbacks_itr != info.callbacks.end()) { + callbacks_itr->second(); + info.callbacks.erase(callbacks_itr); + } + itr = info.callback_id.erase(itr); + } else { + ++itr; + } + } + } +} diff --git a/parse-resolver-runtime/lifecycle.hh b/parse-resolver-runtime/lifecycle.hh new file mode 100644 index 0000000..4e3576d --- /dev/null +++ b/parse-resolver-runtime/lifecycle.hh @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include "ecsact/runtime/common.h" + +namespace ecsact::interpret::details { + +enum class event_ref_id : int; + +class event_ref; + +/** + * IDs that can be destroyed callbacks + */ +using destroyable_id_t = std::variant< // + ecsact_package_id, + ecsact_component_id, + ecsact_transient_id, + ecsact_system_id, + ecsact_action_id>; + +using castable_destroyable_ids_t = std::variant< // + ecsact_package_id, + ecsact_component_id, + ecsact_transient_id, + ecsact_system_id, + ecsact_action_id, + + // castables + ecsact_component_like_id, + ecsact_composite_id, + ecsact_system_like_id, + ecsact_decl_id>; + +/** + * Call @p callback when declaration with @p id is destroyed + */ +auto on_destroy( // + castable_destroyable_ids_t id, + std::function callback +) -> event_ref; + +auto trigger_on_destroy(destroyable_id_t id) -> void; + +class event_ref { + friend auto on_destroy(castable_destroyable_ids_t, std::function) + -> event_ref; + + int destroyable_index_; + event_ref_id id_; + + event_ref(); + +public: + event_ref(event_ref&&); + ~event_ref(); + auto clear() -> void; +}; +} // namespace ecsact::interpret::details diff --git a/parse-resolver-runtime/parse-resolver-runtime.cc b/parse-resolver-runtime/parse-resolver-runtime.cc index 939d3f6..b030178 100644 --- a/parse-resolver-runtime/parse-resolver-runtime.cc +++ b/parse-resolver-runtime/parse-resolver-runtime.cc @@ -9,9 +9,11 @@ #include #include #include -#include #include #include +#include "parse-resolver-runtime/lifecycle.hh" + +using ecsact::interpret::details::trigger_on_destroy; struct field { std::string name; @@ -44,8 +46,7 @@ struct system_like { std::unordered_map; struct cap_entry { - ecsact_system_capability cap; - std::unordered_map assoc; + ecsact_system_capability cap; }; struct gen_entry { @@ -143,7 +144,9 @@ static ecsact_package_id owner_package_id(T id) { template void visit_each_def_collection(Callback&& callback) { callback(comp_defs); + callback(trans_defs); callback(sys_defs); + callback(act_defs); } template @@ -220,6 +223,7 @@ void ecsact_destroy_package(ecsact_package_id package_id) { if(owner_package_id(itr->first) != package_id) { ++itr; } else { + trigger_on_destroy(itr->first); itr = defs.erase(itr); } } @@ -233,6 +237,8 @@ void ecsact_destroy_package(ecsact_package_id package_id) { owner_itr = def_owner_map.erase(owner_itr); } } + + trigger_on_destroy(package_id); } int32_t ecsact_meta_count_packages() { @@ -661,7 +667,7 @@ static auto enum_type_size(ecsact_enum_id enum_id) { return builtin_type_size(ecsact_meta_enum_storage_type(enum_id)); } -static auto field_type_size(ecsact_field_type type) { +static auto field_type_size(ecsact_field_type type) -> int32_t { auto base_size = 0; switch(type.kind) { case ECSACT_TYPE_KIND_BUILTIN: @@ -670,6 +676,12 @@ static auto field_type_size(ecsact_field_type type) { case ECSACT_TYPE_KIND_ENUM: base_size = enum_type_size(type.type.enum_id); break; + case ECSACT_TYPE_KIND_FIELD_INDEX: + base_size = field_type_size(ecsact_meta_field_type( + type.type.field_index.composite_id, + type.type.field_index.field_id + )); + break; } return base_size * type.length; @@ -746,31 +758,6 @@ void ecsact_meta_system_capabilities( } } -void ecsact_set_system_association_capability( - ecsact_system_like_id sys_id, - ecsact_component_like_id comp_id, - ecsact_field_id with_entity_field_id, - ecsact_component_like_id with_comp_id, - ecsact_system_capability with_comp_cap -) { - auto& def = get_system_like(sys_id); - auto& assoc_field = def.caps.at(comp_id).assoc[with_entity_field_id]; - assoc_field[with_comp_id] = with_comp_cap; -} - -void ecsact_unset_system_association_capability( - ecsact_system_like_id sys_id, - ecsact_component_like_id comp_id, - ecsact_field_id with_entity_field_id, - ecsact_component_like_id with_comp_id -) { - auto& def = get_system_like(sys_id); - assert(def.caps.contains(comp_id)); - assert(def.caps.at(comp_id).assoc.contains(with_entity_field_id)); - auto& assoc_field = def.caps.at(comp_id).assoc.at(with_entity_field_id); - assoc_field.erase(with_comp_id); -} - void ecsact_remove_child_system( ecsact_system_like_id parent, ecsact_system_id child @@ -1070,90 +1057,6 @@ void ecsact_meta_system_generates_components( } } -int32_t ecsact_meta_system_association_fields_count( - ecsact_system_like_id system_id, - ecsact_component_like_id component_id -) { - auto& def = get_system_like(system_id); - auto& caps = def.caps.at(component_id); - - return static_cast(caps.assoc.size()); -} - -void ecsact_meta_system_association_fields( - ecsact_system_like_id system_id, - ecsact_component_like_id component_id, - int32_t max_fields_count, - ecsact_field_id* out_fields, - int32_t* out_fields_count -) { - auto& def = get_system_like(system_id); - auto& caps = def.caps.at(component_id); - - auto itr = caps.assoc.begin(); - for(int i = 0; max_fields_count > i; ++i, ++itr) { - if(itr == caps.assoc.end()) { - break; - } - - out_fields[i] = itr->first; - } - - if(out_fields_count != nullptr) { - *out_fields_count = static_cast(caps.assoc.size()); - } -} - -int32_t ecsact_meta_system_association_capabilities_count( - ecsact_system_like_id system_id, - ecsact_component_like_id component_id, - ecsact_field_id field_id -) { - auto& def = get_system_like(system_id); - auto& caps = def.caps.at(component_id); - if(caps.assoc.contains(field_id)) { - auto& assoc_field = caps.assoc.at(field_id); - return static_cast(assoc_field.size()); - } - - return 0; -} - -void ecsact_meta_system_association_capabilities( - ecsact_system_like_id system_id, - ecsact_component_like_id component_id, - ecsact_field_id field_id, - int32_t max_capabilities_count, - ecsact_component_like_id* out_capability_component_ids, - ecsact_system_capability* out_capabilities, - int32_t* out_capabilities_count -) { - auto& def = get_system_like(system_id); - auto& caps = def.caps.at(component_id); - - if(caps.assoc.contains(field_id)) { - auto& assoc_field = caps.assoc.at(field_id); - - auto itr = assoc_field.begin(); - for(int i = 0; max_capabilities_count > i; ++i, ++itr) { - if(itr == assoc_field.end()) { - break; - } - - out_capability_component_ids[i] = itr->first; - out_capabilities[i] = itr->second; - } - - if(out_capabilities_count != nullptr) { - *out_capabilities_count = static_cast(assoc_field.size()); - } - } else { - if(out_capabilities_count != nullptr) { - *out_capabilities_count = 0; - } - } -} - void ecsact_set_system_lazy_iteration_rate( // ecsact_system_id system_id, int32_t iteration_rate diff --git a/test/MODULE.bazel b/test/MODULE.bazel index c499f4e..6cd140f 100644 --- a/test/MODULE.bazel +++ b/test/MODULE.bazel @@ -3,8 +3,13 @@ module(name = "ecsact_interpret_test") bazel_dep(name = "rules_cc", version = "0.0.9") bazel_dep(name = "bazel_skylib", version = "1.5.0") bazel_dep(name = "googletest", version = "1.14.0") -bazel_dep(name = "ecsact_parse", version = "0.4.0") -bazel_dep(name = "ecsact_runtime", version = "0.6.1") +bazel_dep(name = "ecsact_parse", version = "0.5.0") +bazel_dep(name = "ecsact_runtime", version = "0.6.3") + +local_path_override( + module_name = "ecsact_runtime", + path = "../../ecsact_runtime", +) bazel_dep(name = "toolchains_llvm", version = "1.0.0", dev_dependency = True) bazel_dep(name = "hedron_compile_commands", dev_dependency = True) diff --git a/test/field_indexing.cc b/test/field_indexing.cc index 30eed8c..5a2a2b3 100644 --- a/test/field_indexing.cc +++ b/test/field_indexing.cc @@ -1,7 +1,6 @@ #include "gtest/gtest.h" -#include "ecsact/interpret/eval.h" -#include "ecsact/runtime/meta.hh" +#include "ecsact/runtime/meta.hh" #include "test_lib.hh" TEST(FieldIndexing, NoErrors) { @@ -11,53 +10,35 @@ TEST(FieldIndexing, NoErrors) { auto pkg_id = ecsact::meta::get_package_ids().at(0); - auto comp_ids = ecsact::meta::get_component_ids(pkg_id); - auto example_comp_id = comp_ids.at(0); - auto example_with_index_field_id = comp_ids.at(1); + auto example_comp = get_component_by_name(pkg_id, "Example"); + ASSERT_TRUE(example_comp); - auto example_with_index_field_id_field_ids = - ecsact::meta::get_field_ids(example_with_index_field_id); - auto example_with_index_field_id_field_id = - example_with_index_field_id_field_ids.at(0); + auto single_field_index_comp = + get_component_by_name(pkg_id, "SingleFieldIndex"); + ASSERT_TRUE(single_field_index_comp); - auto example_comp_field_ids = ecsact::meta::get_field_ids(example_comp_id); - auto example_comp_num_field_id = example_comp_field_ids.at(0); + auto field_index_action = get_action_by_name(pkg_id, "FieldIndexAction"); + ASSERT_TRUE(field_index_action); - auto act_id = ecsact::meta::get_action_ids(pkg_id).at(0); + auto multi_field_comp = get_component_by_name(pkg_id, "MultiField"); + ASSERT_TRUE(multi_field_comp); - auto act_field_ids = ecsact::meta::get_field_ids(act_id); - ASSERT_EQ(act_field_ids.size(), 1); - auto act_field_id = act_field_ids.at(0); + auto indexed_multi_field = get_component_by_name(pkg_id, "IndexedMultiField"); + ASSERT_TRUE(indexed_multi_field); - auto act_field_type = ecsact_meta_field_type( - ecsact_id_cast(act_id), - act_field_id - ); + auto multi_field_index_system = + get_system_by_name(pkg_id, "MultiFieldIndexSystem"); + ASSERT_TRUE(multi_field_index_system); - ASSERT_EQ(act_field_type.kind, ECSACT_TYPE_KIND_FIELD_INDEX); - ASSERT_EQ( - act_field_type.type.field_index.composite_id, - ecsact_id_cast(example_comp_id) - ); - ASSERT_EQ( - act_field_type.type.field_index.field_id, - example_comp_num_field_id - ); - ASSERT_EQ(act_field_type.length, 0); - - auto comp_field_type = ecsact_meta_field_type( - ecsact_id_cast(example_with_index_field_id), - example_with_index_field_id_field_id - ); + auto multi_field_index_system_assoc_ids = + ecsact::meta::system_assoc_ids(*multi_field_index_system); + ASSERT_EQ(multi_field_index_system_assoc_ids.size(), 1); - ASSERT_EQ(comp_field_type.kind, ECSACT_TYPE_KIND_FIELD_INDEX); - ASSERT_EQ( - comp_field_type.type.field_index.composite_id, - ecsact_id_cast(example_comp_id) - ); ASSERT_EQ( - comp_field_type.type.field_index.field_id, - example_comp_num_field_id + ecsact::meta::system_assoc_component_id( + *multi_field_index_system, + multi_field_index_system_assoc_ids.at(0) + ), + ecsact_id_cast(*indexed_multi_field) ); - ASSERT_EQ(comp_field_type.length, 0); } diff --git a/test/field_indexing.ecsact b/test/field_indexing.ecsact index d200510..2558ad0 100644 --- a/test/field_indexing.ecsact +++ b/test/field_indexing.ecsact @@ -1,15 +1,23 @@ package eval.field_indexing; -component Example { - i32 num; -} - -component ExampleComponentWithIndexedField { - Example.num hello; -} +component Example { i32 num; } +component SingleFieldIndex { Example.num hello; } -action ExampleActionWithIndexedField { +action FieldIndexActon { Example.num cool_field_name; readonly Example; } + +component MultiField { i32 x; i32 y; } +component IndexedMultiField { + MultiExample.x indexed_x; + MultiExample.y indexed_y; + i32 other_field; +} + +system MultiFieldIndexSystem { + readwrite IndexedMultiField with indexed_x,indexed_y { + readwrite Example; + } +} diff --git a/test/test_lib.hh b/test/test_lib.hh index 1891f5b..f9ace71 100644 --- a/test/test_lib.hh +++ b/test/test_lib.hh @@ -3,10 +3,52 @@ #include #include #include +#include +#include #include "gtest/gtest.h" #include "ecsact/interpret/eval.hh" +#include "ecsact/runtime/meta.hh" #include "bazel_sundry/runfiles.hh" +inline auto get_component_by_name( // + ecsact_package_id pkg_id, + std::string name +) -> std::optional { + for(auto comp_id : ecsact::meta::get_component_ids(pkg_id)) { + if(ecsact::meta::component_name(comp_id) == name) { + return comp_id; + } + } + + return {}; +} + +inline auto get_system_by_name( // + ecsact_package_id pkg_id, + std::string name +) -> std::optional { + for(auto sys_id : ecsact::meta::get_system_ids(pkg_id)) { + if(ecsact::meta::system_name(sys_id) == name) { + return sys_id; + } + } + + return {}; +} + +inline auto get_action_by_name( // + ecsact_package_id pkg_id, + std::string name +) -> std::optional { + for(auto act_id : ecsact::meta::get_action_ids(pkg_id)) { + if(ecsact::meta::action_name(act_id) == name) { + return act_id; + } + } + + return {}; +} + inline auto ecsact_interpret_test_files( std::vector relative_file_paths ) -> std::vector { From 2092c183393d62043530f3ae570e8761b1c69613 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Fri, 24 May 2024 16:22:58 -0700 Subject: [PATCH 04/10] chore: cleanup includes --- ecsact/interpret/eval.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ecsact/interpret/eval.cc b/ecsact/interpret/eval.cc index fccaf54..2a1c53c 100644 --- a/ecsact/interpret/eval.cc +++ b/ecsact/interpret/eval.cc @@ -13,9 +13,8 @@ #include "ecsact/runtime/dynamic.h" #include "ecsact/runtime/meta.hh" #include "ecsact/runtime/meta.h" - -#include "./detail/file_eval_error.hh" -#include "eval_error.h" +#include "ecsact/interpret/detail/file_eval_error.hh" +#include "ecsact/interpret/eval_error.h" using namespace std::string_literals; using namespace std::string_view_literals; From 861bb6f9d5d093df8387ac8a533fd19cef92e1f0 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Fri, 24 May 2024 16:23:53 -0700 Subject: [PATCH 05/10] chore: fix typos --- ecsact/interpret/eval.h | 2 +- parse-resolver-runtime/lifecycle.cc | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ecsact/interpret/eval.h b/ecsact/interpret/eval.h index 2f14fe5..756cb88 100644 --- a/ecsact/interpret/eval.h +++ b/ecsact/interpret/eval.h @@ -32,7 +32,7 @@ ecsact_eval_error ecsact_eval_statement( const ecsact_statement* statement_stack ); -ECSACT_DEPRECATED("uneeded since interpreter does not hold state") +ECSACT_DEPRECATED("unneeded since interpreter does not hold state") void ecsact_eval_reset(); #endif // ECSACT_INTERPRET_EVAL_H diff --git a/parse-resolver-runtime/lifecycle.cc b/parse-resolver-runtime/lifecycle.cc index e03f092..711a79e 100644 --- a/parse-resolver-runtime/lifecycle.cc +++ b/parse-resolver-runtime/lifecycle.cc @@ -7,7 +7,7 @@ using ecsact::interpret::details::castable_destroyable_ids_t; using ecsact::interpret::details::destroyable_id_t; using ecsact::interpret::details::event_ref_id; -struct lifecycle_calback_info { +struct lifecycle_callback_info { event_ref_id last_event_ref_id = {}; std::unordered_map callback_id; std::unordered_map> callbacks; @@ -20,7 +20,7 @@ struct lifecycle_calback_info { }; static std::array< // - lifecycle_calback_info, + lifecycle_callback_info, std::variant_size_v> lifecycle_info = {}; @@ -32,7 +32,7 @@ static auto destroyable_id_as_int(destroyable_id_t id) -> int { return std::visit([](auto id) { return static_cast(id); }, id); } -static auto callback_indicies(destroyable_id_t id) -> std::vector { +static auto callback_indices(destroyable_id_t id) -> std::vector { auto result = std::vector{}; result.emplace_back(static_cast(id.index())); @@ -101,7 +101,7 @@ auto ecsact::interpret::details::on_destroy( // auto ecsact::interpret::details::trigger_on_destroy( // destroyable_id_t id ) -> void { - for(auto index : callback_indicies(id)) { + for(auto index : callback_indices(id)) { auto& info = lifecycle_info[index]; for(auto itr = info.callback_id.begin(); itr != info.callback_id.end();) { auto& event_ref = itr->first; From bfdf9d8f0dd4999a00ab5015bdec0bcd0bf4c865 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Fri, 24 May 2024 18:17:31 -0700 Subject: [PATCH 06/10] chore: more wip --- ecsact/interpret/eval.cc | 133 ++++++++++++++++++++++++++++ ecsact/interpret/eval_error.h | 4 + parse-resolver-runtime/assoc.cc | 13 +++ parse-resolver-runtime/ids.cc | 2 +- parse-resolver-runtime/lifecycle.cc | 11 ++- test/field_indexing.cc | 105 +++++++++++++++++----- test/field_indexing.ecsact | 13 ++- test/test.cc | 8 +- test/test_lib.hh | 18 ++++ 9 files changed, 275 insertions(+), 32 deletions(-) diff --git a/ecsact/interpret/eval.cc b/ecsact/interpret/eval.cc index 2a1c53c..f0db42b 100644 --- a/ecsact/interpret/eval.cc +++ b/ecsact/interpret/eval.cc @@ -1,5 +1,6 @@ #include "ecsact/interpret/eval.h" +#include #include #include #include @@ -41,6 +42,7 @@ static auto expect_context( } if(context_stack.empty()) { + __debugbreak(); return { nullptr, ecsact_eval_error{ @@ -58,6 +60,7 @@ static auto expect_context( } } + __debugbreak(); return { &context, ecsact_eval_error{ @@ -756,6 +759,7 @@ static ecsact_eval_error eval_system_statement( parent_sys_like_id = find_by_statement(package_id, *context); if(!parent_sys_like_id) { + __debugbreak(); return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, .relevant_content = {}, @@ -891,6 +895,7 @@ static ecsact_eval_error eval_enum_value_statement( auto enum_id = find_by_name(package_id, enum_name); if(!enum_id) { + __debugbreak(); return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, .relevant_content = context_data.enum_name, @@ -927,6 +932,7 @@ static ecsact_eval_error eval_builtin_type_field_statement( auto compo_id = find_by_statement(package_id, *context); if(!compo_id) { + __debugbreak(); return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, .relevant_content = {}, @@ -986,6 +992,7 @@ static ecsact_eval_error eval_user_type_field_statement( auto compo_id = find_by_statement(package_id, context_stack.back()); if(!compo_id) { + __debugbreak(); return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, .relevant_content = {}, @@ -1053,6 +1060,35 @@ static ecsact_eval_error eval_entity_field_statement( ); } +static auto get_with_field_ids( + ecsact_system_like_id sys_like_id, + ecsact_component_like_id comp_like_id, + std::span fields +) -> std::vector { + auto with_field_ids = std::vector{}; + for(int i = 0; fields.size() > i; ++i) { + auto assoc_field_name = + std::string_view{fields[i].data, static_cast(fields[i].length)}; + + auto assoc_field_id = std::optional{}; + + for(auto field_id : ecsact::meta::get_field_ids(comp_like_id)) { + std::string field_name = ecsact_meta_field_name( + ecsact_id_cast(comp_like_id), + field_id + ); + if(assoc_field_name == field_name) { + assoc_field_id = field_id; + break; + } + } + + assert(assoc_field_id.has_value()); + with_field_ids.emplace_back(*assoc_field_id); + } + return with_field_ids; +} + static auto eval_system_with_statement_data_common( ecsact_system_like_id sys_like_id, ecsact_component_like_id comp_like_id, @@ -1082,6 +1118,8 @@ static auto eval_system_with_statement_data_common( .relevant_content = fields[i], }; } + + with_field_ids.emplace_back(*assoc_field_id); } if(with_field_ids.empty()) { @@ -1100,6 +1138,41 @@ static auto eval_system_with_statement_data_common( return {}; } +template +static auto find_assoc_ids_with_fields( // + SystemLikeID sys_like_id, + auto target_fields +) -> std::vector { + auto assoc_ids = std::set{}; + for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { + auto fields = ecsact::meta::system_assoc_fields(sys_like_id, assoc_id); + auto matching_fields = std::vector{}; + for(auto field : fields) { + auto found_target_field = false; + for(auto target_field : target_fields) { + if(field != target_field) { + found_target_field = true; + matching_fields.push_back(field); + } + } + + if(!found_target_field) { + break; + } + } + + assert(matching_fields.size() <= fields.size()); + if(matching_fields.size() == fields.size()) { + assoc_ids.insert(assoc_id); + } + } + + return std::vector{ + assoc_ids.begin(), + assoc_ids.end() + }; +} + static ecsact_eval_error eval_system_component_statement( ecsact_package_id package_id, std::span& context_stack, @@ -1111,6 +1184,7 @@ static ecsact_eval_error eval_system_component_statement( ECSACT_STATEMENT_SYSTEM, ECSACT_STATEMENT_ACTION, ECSACT_STATEMENT_SYSTEM_COMPONENT, + ECSACT_STATEMENT_SYSTEM_WITH, } ); @@ -1180,6 +1254,64 @@ static ecsact_eval_error eval_system_component_statement( break; } + // system Example { + // readwrite ExampleComponent { + // with blah { + // readwrite ExampleComponent <-- we are here + // } + // } + // } + case ECSACT_STATEMENT_SYSTEM_WITH: { + if(context_stack.size() < 3) { + return ecsact_eval_error{ + .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, + .relevant_content = {}, + }; + } + sys_like_id = find_by_statement( + package_id, + context_stack[context_stack.size() - 3] + ); + if(!sys_like_id) { + return ecsact_eval_error{ + .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, + .relevant_content = {}, + }; + } + + auto assoc_comp_id = find_by_statement( + package_id, + context_stack[context_stack.size() - 2] + ); + if(!assoc_comp_id) { + return ecsact_eval_error{ + .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, + .relevant_content = {}, + }; + } + + auto fields = get_with_field_ids( + *sys_like_id, + *comp_like_id, + std::span{ + std::data(context->data.system_with_statement.with_field_name_list), + static_cast( + context->data.system_with_statement.with_field_name_list_count + ) + } + ); + + auto assoc_ids = find_assoc_ids_with_fields(*sys_like_id, fields); + + if(assoc_ids.size() > 1) { + return ecsact_eval_error{ + .code = ECSACT_EVAL_ERR_SAME_FIELDS_SYSTEM_ASSOCIATION, + .relevant_content = {}, + }; + } + + break; + } default: return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, @@ -1268,6 +1400,7 @@ static ecsact_eval_error eval_system_generates_statement( find_by_statement(package_id, context_stack.back()); if(!sys_like_id) { + __debugbreak(); return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, .relevant_content = {}, diff --git a/ecsact/interpret/eval_error.h b/ecsact/interpret/eval_error.h index 07e2704..8869941 100644 --- a/ecsact/interpret/eval_error.h +++ b/ecsact/interpret/eval_error.h @@ -81,6 +81,10 @@ typedef enum ecsact_eval_error_code { /// Nested association is not allowed ECSACT_EVAL_ERR_NESTED_ASSOC, + /// Interpreter limitation. Association with same fields in same system are + /// currently not allowed. + ECSACT_EVAL_ERR_SAME_FIELDS_SYSTEM_ASSOCIATION, + /// Internal error. Should not happen and is an indiciation of a bug. ECSACT_EVAL_ERR_INTERNAL = 999, diff --git a/parse-resolver-runtime/assoc.cc b/parse-resolver-runtime/assoc.cc index ee1bfc5..e0f1cf3 100644 --- a/parse-resolver-runtime/assoc.cc +++ b/parse-resolver-runtime/assoc.cc @@ -236,6 +236,19 @@ void ecsact_meta_system_assoc_ids( } } +ecsact_component_like_id ecsact_meta_system_assoc_component_id( + ecsact_system_like_id system_id, + ecsact_system_assoc_id assoc_id +) { + auto info = get_assoc_info(system_id, assoc_id); + if(!info) { + // Invalid assoc. User error. + return ECSACT_INVALID_ID(component_like); + } + + return info->comp_id; +} + int32_t ecsact_meta_system_assoc_fields_count( ecsact_system_like_id system_id, ecsact_system_assoc_id assoc_id diff --git a/parse-resolver-runtime/ids.cc b/parse-resolver-runtime/ids.cc index e5237e5..da5bc20 100644 --- a/parse-resolver-runtime/ids.cc +++ b/parse-resolver-runtime/ids.cc @@ -8,7 +8,7 @@ static std::atomic_int32_t last_id = 0; auto ecsact::interpret::details::gen_next_id_() -> int32_t { // Getting here would be crazy and if we were to do anything about it we'd // have to implement an "ID recycling" mechanism which I think is overkill. - if(last_id == std::numeric_limits::max()) { + if(last_id == std::numeric_limits::max()) { throw std::logic_error{"Max id count reached"}; } diff --git a/parse-resolver-runtime/lifecycle.cc b/parse-resolver-runtime/lifecycle.cc index 711a79e..fcfd29e 100644 --- a/parse-resolver-runtime/lifecycle.cc +++ b/parse-resolver-runtime/lifecycle.cc @@ -79,8 +79,17 @@ auto ecsact::interpret::details::event_ref::clear() -> void { return; } + if(destroyable_index_ >= lifecycle_info.size()) { + return; + } + auto& info = lifecycle_info[destroyable_index_]; - info.callbacks.erase(id_); + // if(info.callbacks.contains(id_)) { + // info.callbacks.erase(id_); + // } + // if(info.callback_id.contains(id_)) { + // info.callback_id.erase(id_); + // } id_ = {}; } diff --git a/test/field_indexing.cc b/test/field_indexing.cc index 5a2a2b3..d5c316f 100644 --- a/test/field_indexing.cc +++ b/test/field_indexing.cc @@ -1,44 +1,103 @@ #include "gtest/gtest.h" #include "ecsact/runtime/meta.hh" +#include "ecsact/runtime/dynamic.h" #include "test_lib.hh" -TEST(FieldIndexing, NoErrors) { - auto errs = ecsact_interpret_test_files({"field_indexing.ecsact"}); - EXPECT_EQ(errs.size(), 0) // - << "Expected no errors. Instead got: " << errs[0].error_message << "\n"; +using ecsact::meta::get_field_type; - auto pkg_id = ecsact::meta::get_package_ids().at(0); +class FieldIndexing : public testing::Test { +public: + ecsact_package_id pkg_id; +protected: + void SetUp() override { + auto errs = ecsact_interpret_test_files({"field_indexing.ecsact"}); + ASSERT_EQ(errs.size(), 0) // + << "Expected no errors. Instead got: " << errs[0].error_message << "\n"; + pkg_id = ecsact::meta::get_package_ids().at(0); + } + + void TearDown() override { + // ecsact_destroy_package(pkg_id); + } +}; + +TEST_F(FieldIndexing, SingleFieldIndex) { + auto example_comp = get_component_by_name(pkg_id, "Example"); + ASSERT_TRUE(example_comp); + + auto comp = get_component_by_name(pkg_id, "SingleFieldIndex"); + ASSERT_TRUE(comp); + + auto field = get_field_by_name(*comp, "hello"); + ASSERT_TRUE(field); + + auto field_type = get_field_type(*comp, *field); + ASSERT_EQ(field_type.kind, ECSACT_TYPE_KIND_FIELD_INDEX); + ASSERT_EQ( + field_type.type.field_index.composite_id, + ecsact_id_cast(*example_comp) + ); +} + +TEST_F(FieldIndexing, FieldIndexAction) { auto example_comp = get_component_by_name(pkg_id, "Example"); ASSERT_TRUE(example_comp); - auto single_field_index_comp = - get_component_by_name(pkg_id, "SingleFieldIndex"); - ASSERT_TRUE(single_field_index_comp); + auto act = get_action_by_name(pkg_id, "FieldIndexAction"); + ASSERT_TRUE(act); + + auto field = get_field_by_name(*act, "cool_field_name"); + ASSERT_TRUE(field); - auto field_index_action = get_action_by_name(pkg_id, "FieldIndexAction"); - ASSERT_TRUE(field_index_action); + auto field_type = get_field_type(*act, *field); + ASSERT_EQ(field_type.kind, ECSACT_TYPE_KIND_FIELD_INDEX); + ASSERT_EQ( + field_type.type.field_index.composite_id, + ecsact_id_cast(*example_comp) + ); +} +TEST_F(FieldIndexing, MutltiField) { auto multi_field_comp = get_component_by_name(pkg_id, "MultiField"); ASSERT_TRUE(multi_field_comp); - auto indexed_multi_field = get_component_by_name(pkg_id, "IndexedMultiField"); - ASSERT_TRUE(indexed_multi_field); + auto comp = get_component_by_name(pkg_id, "IndexedMultiField"); + ASSERT_TRUE(comp); + + auto field_x = get_field_by_name(*comp, "indexed_x"); + auto field_y = get_field_by_name(*comp, "indexed_y"); + ASSERT_TRUE(field_x); + ASSERT_TRUE(field_y); + + auto field_x_type = get_field_type(*comp, *field_x); + auto field_y_type = get_field_type(*comp, *field_x); + + ASSERT_EQ(field_x_type.kind, ECSACT_TYPE_KIND_FIELD_INDEX); + ASSERT_EQ( + field_x_type.type.field_index.composite_id, + ecsact_id_cast(*multi_field_comp) + ); + ASSERT_EQ(field_y_type.kind, ECSACT_TYPE_KIND_FIELD_INDEX); + ASSERT_EQ( + field_y_type.type.field_index.composite_id, + ecsact_id_cast(*multi_field_comp) + ); +} + +TEST_F(FieldIndexing, MultiFieldSystem) { + auto comp = get_component_by_name(pkg_id, "IndexedMultiField"); + ASSERT_TRUE(comp); - auto multi_field_index_system = - get_system_by_name(pkg_id, "MultiFieldIndexSystem"); - ASSERT_TRUE(multi_field_index_system); + auto sys = get_system_by_name(pkg_id, "MultiFieldIndexSystem"); + ASSERT_TRUE(sys); - auto multi_field_index_system_assoc_ids = - ecsact::meta::system_assoc_ids(*multi_field_index_system); - ASSERT_EQ(multi_field_index_system_assoc_ids.size(), 1); + auto assoc_ids = ecsact::meta::system_assoc_ids(*sys); + ASSERT_EQ(assoc_ids.size(), 1); ASSERT_EQ( - ecsact::meta::system_assoc_component_id( - *multi_field_index_system, - multi_field_index_system_assoc_ids.at(0) - ), - ecsact_id_cast(*indexed_multi_field) + ecsact::meta::system_assoc_component_id(*sys, assoc_ids.at(0)), + ecsact_id_cast(*comp) ); } diff --git a/test/field_indexing.ecsact b/test/field_indexing.ecsact index 2558ad0..b1f8afb 100644 --- a/test/field_indexing.ecsact +++ b/test/field_indexing.ecsact @@ -3,7 +3,7 @@ package eval.field_indexing; component Example { i32 num; } component SingleFieldIndex { Example.num hello; } -action FieldIndexActon { +action FieldIndexAction { Example.num cool_field_name; readonly Example; @@ -11,8 +11,8 @@ action FieldIndexActon { component MultiField { i32 x; i32 y; } component IndexedMultiField { - MultiExample.x indexed_x; - MultiExample.y indexed_y; + MultiField.x indexed_x; + MultiField.y indexed_y; i32 other_field; } @@ -21,3 +21,10 @@ system MultiFieldIndexSystem { readwrite Example; } } + +system MultiFieldSeparateWithSystem { + readwrite IndexedMultiField { + with indexed_x { readwrite Example; } + with indexed_y { readwrite Example; } + } +} diff --git a/test/test.cc b/test/test.cc index c36d311..40e3afe 100644 --- a/test/test.cc +++ b/test/test.cc @@ -123,10 +123,10 @@ TEST(EcsactParseRuntimeInterop, Simple) { ); ASSERT_EQ(sys_caps[0], ECSACT_SYS_CAP_READWRITE); - auto assoc_fields = ecsact::meta::system_association_fields( - sys_like_id, - ecsact_id_cast(comp_id) - ); + auto assoc_ids = ecsact::meta::system_assoc_ids(sys_like_id); + ASSERT_EQ(assoc_ids.size(), 1); + auto assoc_fields = + ecsact::meta::system_assoc_fields(sys_like_id, assoc_ids.at(0)); ASSERT_EQ(assoc_fields.size(), 1); auto field_id = *assoc_fields.begin(); auto assoc_field_name = ecsact_meta_field_name( diff --git a/test/test_lib.hh b/test/test_lib.hh index f9ace71..9bf3bf3 100644 --- a/test/test_lib.hh +++ b/test/test_lib.hh @@ -49,6 +49,24 @@ inline auto get_action_by_name( // return {}; } +template +inline auto get_field_by_name( // + CompositeID id, + std::string target_field_name +) -> std::optional { + auto field_ids = ecsact::meta::get_field_ids(id); + for(auto field_id : field_ids) { + std::string field_name = + ecsact_meta_field_name(ecsact_id_cast(id), field_id); + + if(field_name == target_field_name) { + return field_id; + } + } + + return {}; +} + inline auto ecsact_interpret_test_files( std::vector relative_file_paths ) -> std::vector { From 77e75b31f78a18fce975b438c4ecc2ac9a7db3cd Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Mon, 27 May 2024 13:35:07 -0700 Subject: [PATCH 07/10] fix: small typos and some cleanup --- ecsact/interpret/eval.cc | 123 +++++++++++++++++++++++++++++++-------- test/BUILD.bazel | 3 +- 2 files changed, 101 insertions(+), 25 deletions(-) diff --git a/ecsact/interpret/eval.cc b/ecsact/interpret/eval.cc index f0db42b..40de65d 100644 --- a/ecsact/interpret/eval.cc +++ b/ecsact/interpret/eval.cc @@ -17,6 +17,9 @@ #include "ecsact/interpret/detail/file_eval_error.hh" #include "ecsact/interpret/eval_error.h" +using ecsact::meta::system_assoc_capabilities; +using ecsact::meta::system_capabilities; + using namespace std::string_literals; using namespace std::string_view_literals; @@ -29,6 +32,10 @@ struct overloaded : Ts... { template overloaded(Ts...) -> overloaded; +auto as_sv(ecsact_statement_sv sv) -> std::string_view { + return std::string_view{sv.data, static_cast(sv.length)}; +} + static auto expect_context( std::span& context_stack, std::vector context_types @@ -555,6 +562,14 @@ std::optional find_by_statement( ) ) ); + case ECSACT_STATEMENT_SYSTEM_COMPONENT: + return find_by_name( + package_id, + std::string( + statement.data.system_component_statement.component_name.data, + statement.data.system_component_statement.component_name.length + ) + ); default: break; } @@ -1138,19 +1153,28 @@ static auto eval_system_with_statement_data_common( return {}; } -template +template static auto find_assoc_ids_with_fields( // - SystemLikeID sys_like_id, - auto target_fields + SystemLikeID sys_like_id, + ComponentLikeID comp_like_id, + auto target_field_names ) -> std::vector { + assert(std::size(target_field_names) > 0); auto assoc_ids = std::set{}; for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { + auto assoc_comp_id = + ecsact::meta::system_assoc_component_id(sys_like_id, assoc_id); + if(assoc_comp_id != comp_like_id) { + continue; + } + auto fields = ecsact::meta::system_assoc_fields(sys_like_id, assoc_id); auto matching_fields = std::vector{}; for(auto field : fields) { + auto field_name = ecsact::meta::field_name(comp_like_id, field); auto found_target_field = false; - for(auto target_field : target_fields) { - if(field != target_field) { + for(auto target_field_name : target_field_names) { + if(field_name == as_sv(target_field_name)) { found_target_field = true; matching_fields.push_back(field); } @@ -1167,6 +1191,8 @@ static auto find_assoc_ids_with_fields( // } } + assert(!assoc_ids.empty()); + return std::vector{ assoc_ids.begin(), assoc_ids.end() @@ -1235,6 +1261,7 @@ static ecsact_eval_error eval_system_component_statement( // } case ECSACT_STATEMENT_SYSTEM_COMPONENT: { if(context_stack.size() < 2) { + __debugbreak(); return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, .relevant_content = {}, @@ -1245,6 +1272,14 @@ static ecsact_eval_error eval_system_component_statement( context_stack[context_stack.size() - 2] ); + if(!sys_like_id) { + __debugbreak(); + return ecsact_eval_error{ + .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, + .relevant_content = {}, + }; + } + if(statement_data.with_field_name_list_count > 0) { return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_NESTED_ASSOC, @@ -1252,6 +1287,35 @@ static ecsact_eval_error eval_system_component_statement( }; } + const auto& context_data = context->data.system_component_statement; + + auto assoc_comp_id = + find_by_statement(package_id, *context); + if(!assoc_comp_id) { + return ecsact_eval_error{ + .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, + .relevant_content = {}, + }; + } + + auto field_names = std::span{ + std::data(context_data.with_field_name_list), + static_cast(context_data.with_field_name_list_count) + }; + + if(!field_names.empty()) { + // NOTE: This is a temporary limitation of the interpreter since there + // isn't a way to get the association ID other than comparing fields. + auto assoc_ids = + find_assoc_ids_with_fields(*sys_like_id, *assoc_comp_id, field_names); + if(assoc_ids.size() > 1) { + return ecsact_eval_error{ + .code = ECSACT_EVAL_ERR_SAME_FIELDS_SYSTEM_ASSOCIATION, + .relevant_content = {}, + }; + } + assoc_id = assoc_ids.at(0); + } break; } // system Example { @@ -1279,6 +1343,8 @@ static ecsact_eval_error eval_system_component_statement( }; } + const auto& context_data = context->data.system_with_statement; + auto assoc_comp_id = find_by_statement( package_id, context_stack[context_stack.size() - 2] @@ -1290,26 +1356,22 @@ static ecsact_eval_error eval_system_component_statement( }; } - auto fields = get_with_field_ids( - *sys_like_id, - *comp_like_id, - std::span{ - std::data(context->data.system_with_statement.with_field_name_list), - static_cast( - context->data.system_with_statement.with_field_name_list_count - ) - } - ); - - auto assoc_ids = find_assoc_ids_with_fields(*sys_like_id, fields); + auto field_names = std::span{ + std::data(context_data.with_field_name_list), + static_cast(context_data.with_field_name_list_count) + }; + // NOTE: This is a temporary limitation of the interpreter since there + // isn't a way to get the association ID other than comparing fields. + auto assoc_ids = + find_assoc_ids_with_fields(*sys_like_id, *assoc_comp_id, field_names); if(assoc_ids.size() > 1) { return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_SAME_FIELDS_SYSTEM_ASSOCIATION, .relevant_content = {}, }; } - + assoc_id = assoc_ids.at(0); break; } default: @@ -1348,12 +1410,25 @@ static ecsact_eval_error eval_system_component_statement( } } - for(auto& entry : ecsact::meta::system_capabilities(*sys_like_id)) { - if(entry.first == *comp_like_id) { - return ecsact_eval_error{ - .code = ECSACT_EVAL_ERR_MULTIPLE_CAPABILITIES_SAME_COMPONENT_LIKE, - .relevant_content = statement_data.component_name, - }; + if(assoc_id) { + for(auto& entry : system_assoc_capabilities(*sys_like_id, *assoc_id)) { + if(entry.first == *comp_like_id) { + __debugbreak(); + return ecsact_eval_error{ + .code = ECSACT_EVAL_ERR_MULTIPLE_CAPABILITIES_SAME_COMPONENT_LIKE, + .relevant_content = statement_data.component_name, + }; + } + } + } else { + for(auto& entry : system_capabilities(*sys_like_id)) { + if(entry.first == *comp_like_id) { + __debugbreak(); + return ecsact_eval_error{ + .code = ECSACT_EVAL_ERR_MULTIPLE_CAPABILITIES_SAME_COMPONENT_LIKE, + .relevant_content = statement_data.component_name, + }; + } } } diff --git a/test/BUILD.bazel b/test/BUILD.bazel index 094c88c..5c1dda9 100644 --- a/test/BUILD.bazel +++ b/test/BUILD.bazel @@ -1,5 +1,5 @@ -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load("@ecsact_interpret//bazel:copts.bzl", "copts") +load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") cc_library( name = "test_lib", @@ -16,6 +16,7 @@ cc_test( name = "test", srcs = ["test.cc"], copts = copts, + args = ["--gtest_catch_exceptions=0"], data = ["test.ecsact"], deps = [ "@ecsact_interpret", From db8e9d2c8d59e84c57018742efcad280f49effe7 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Mon, 27 May 2024 13:42:37 -0700 Subject: [PATCH 08/10] chore: minor fixes --- test/errors/unknown_association_field.cc | 3 +-- test/test_lib.hh | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/errors/unknown_association_field.cc b/test/errors/unknown_association_field.cc index 79484ed..196b42b 100644 --- a/test/errors/unknown_association_field.cc +++ b/test/errors/unknown_association_field.cc @@ -1,5 +1,4 @@ #include "gtest/gtest.h" -#include "ecsact/interpret/eval.h" #include "test_lib.hh" @@ -7,5 +6,5 @@ TEST(InterpretError, UnknownAssociationField) { auto errs = ecsact_interpret_test_files({"errors/unknown_association_field.ecsact"}); ASSERT_EQ(errs.size(), 1); - ASSERT_EQ(errs[0].eval_error, ECSACT_EVAL_ERR_FIELD_NAME_ALREADY_EXISTS); + ASSERT_EQ(errs[0].eval_error, ECSACT_EVAL_ERR_UNKNOWN_FIELD_NAME); } diff --git a/test/test_lib.hh b/test/test_lib.hh index 9bf3bf3..f79c67c 100644 --- a/test/test_lib.hh +++ b/test/test_lib.hh @@ -8,6 +8,7 @@ #include "gtest/gtest.h" #include "ecsact/interpret/eval.hh" #include "ecsact/runtime/meta.hh" +#include "magic_enum.hpp" #include "bazel_sundry/runfiles.hh" inline auto get_component_by_name( // From 733d492b3b30784b1698e9b9ef83a6c09249a47e Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Mon, 27 May 2024 13:45:47 -0700 Subject: [PATCH 09/10] chore: remove some debug fn calls --- ecsact/interpret/eval.cc | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/ecsact/interpret/eval.cc b/ecsact/interpret/eval.cc index 40de65d..93c7383 100644 --- a/ecsact/interpret/eval.cc +++ b/ecsact/interpret/eval.cc @@ -49,7 +49,6 @@ static auto expect_context( } if(context_stack.empty()) { - __debugbreak(); return { nullptr, ecsact_eval_error{ @@ -67,7 +66,6 @@ static auto expect_context( } } - __debugbreak(); return { &context, ecsact_eval_error{ @@ -774,7 +772,6 @@ static ecsact_eval_error eval_system_statement( parent_sys_like_id = find_by_statement(package_id, *context); if(!parent_sys_like_id) { - __debugbreak(); return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, .relevant_content = {}, @@ -910,7 +907,6 @@ static ecsact_eval_error eval_enum_value_statement( auto enum_id = find_by_name(package_id, enum_name); if(!enum_id) { - __debugbreak(); return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, .relevant_content = context_data.enum_name, @@ -947,7 +943,6 @@ static ecsact_eval_error eval_builtin_type_field_statement( auto compo_id = find_by_statement(package_id, *context); if(!compo_id) { - __debugbreak(); return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, .relevant_content = {}, @@ -1007,7 +1002,6 @@ static ecsact_eval_error eval_user_type_field_statement( auto compo_id = find_by_statement(package_id, context_stack.back()); if(!compo_id) { - __debugbreak(); return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, .relevant_content = {}, @@ -1261,7 +1255,6 @@ static ecsact_eval_error eval_system_component_statement( // } case ECSACT_STATEMENT_SYSTEM_COMPONENT: { if(context_stack.size() < 2) { - __debugbreak(); return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, .relevant_content = {}, @@ -1273,7 +1266,6 @@ static ecsact_eval_error eval_system_component_statement( ); if(!sys_like_id) { - __debugbreak(); return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, .relevant_content = {}, @@ -1413,7 +1405,6 @@ static ecsact_eval_error eval_system_component_statement( if(assoc_id) { for(auto& entry : system_assoc_capabilities(*sys_like_id, *assoc_id)) { if(entry.first == *comp_like_id) { - __debugbreak(); return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_MULTIPLE_CAPABILITIES_SAME_COMPONENT_LIKE, .relevant_content = statement_data.component_name, @@ -1423,7 +1414,6 @@ static ecsact_eval_error eval_system_component_statement( } else { for(auto& entry : system_capabilities(*sys_like_id)) { if(entry.first == *comp_like_id) { - __debugbreak(); return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_MULTIPLE_CAPABILITIES_SAME_COMPONENT_LIKE, .relevant_content = statement_data.component_name, @@ -1475,7 +1465,6 @@ static ecsact_eval_error eval_system_generates_statement( find_by_statement(package_id, context_stack.back()); if(!sys_like_id) { - __debugbreak(); return ecsact_eval_error{ .code = ECSACT_EVAL_ERR_INVALID_CONTEXT, .relevant_content = {}, From ef609a10694a2c18988111f35e09662323cb92e9 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Mon, 27 May 2024 14:02:16 -0700 Subject: [PATCH 10/10] chore: update deps --- MODULE.bazel | 7 +------ test/MODULE.bazel | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 2e38443..d870fea 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -7,14 +7,9 @@ module( bazel_dep(name = "rules_cc", version = "0.0.9") bazel_dep(name = "bazel_skylib", version = "1.5.0") bazel_dep(name = "magic_enum", version = "0.9.3") -bazel_dep(name = "ecsact_runtime", version = "0.6.3") +bazel_dep(name = "ecsact_runtime", version = "0.6.4") bazel_dep(name = "ecsact_parse", version = "0.5.0") -local_path_override( - module_name = "ecsact_runtime", - path = "../ecsact_runtime", -) - bazel_dep(name = "toolchains_llvm", version = "1.0.0", dev_dependency = True) bazel_dep(name = "hedron_compile_commands", dev_dependency = True) git_override( diff --git a/test/MODULE.bazel b/test/MODULE.bazel index 6cd140f..b9d2897 100644 --- a/test/MODULE.bazel +++ b/test/MODULE.bazel @@ -4,12 +4,7 @@ bazel_dep(name = "rules_cc", version = "0.0.9") bazel_dep(name = "bazel_skylib", version = "1.5.0") bazel_dep(name = "googletest", version = "1.14.0") bazel_dep(name = "ecsact_parse", version = "0.5.0") -bazel_dep(name = "ecsact_runtime", version = "0.6.3") - -local_path_override( - module_name = "ecsact_runtime", - path = "../../ecsact_runtime", -) +bazel_dep(name = "ecsact_runtime", version = "0.6.4") bazel_dep(name = "toolchains_llvm", version = "1.0.0", dev_dependency = True) bazel_dep(name = "hedron_compile_commands", dev_dependency = True)