diff --git a/.editorconfig b/.editorconfig index 250ffac..faea8cb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,6 +3,7 @@ root = true [*] end_of_line = lf insert_final_newline = true +indent_size = 4 [*.{cc,hh,cpp,hpp}] # matching .clang-format IndentWidth diff --git a/MODULE.bazel b/MODULE.bazel index c55dd59..dea5e6b 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -7,8 +7,8 @@ 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.9") -bazel_dep(name = "ecsact_parse", version = "0.5.1") +bazel_dep(name = "ecsact_runtime", version = "0.7.0") +bazel_dep(name = "ecsact_parse", version = "0.5.2") 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 5433422..77fdd2b 100644 --- a/ecsact/interpret/eval.cc +++ b/ecsact/interpret/eval.cc @@ -726,10 +726,46 @@ static ecsact_eval_error eval_component_statement( return err; } - if(auto err = disallow_statement_params(statement, context)) { + constexpr auto allowed_params = std::array{"stream"sv, "transient"sv}; + if(auto err = allow_statement_params(statement, context, allowed_params)) { return *err; } + auto stream_param = + statement_param(statement, "stream"sv); + auto transient_param = statement_param(statement, "transient"sv); + auto component_type = ECSACT_COMPONENT_TYPE_NONE; + + if(stream_param) { + auto stream_type = std::get_if(&stream_param.value()); + if(stream_type) { + if(*stream_type != "lazy"sv) { + return ecsact_eval_error{ + .code = ECSACT_EVAL_ERR_INVALID_PARAMETER_VALUE, + .relevant_content = statement.parameters[0].name, + }; + } + + component_type = ECSACT_COMPONENT_TYPE_LAZY_STREAM; + } else if(std::get(stream_param.value())) { + component_type = ECSACT_COMPONENT_TYPE_STREAM; + } + } + + if(transient_param) { + if(transient_param.value()) { + if(component_type != ECSACT_COMPONENT_TYPE_NONE) { + // can't have transient stream + return ecsact_eval_error{ + .code = ECSACT_EVAL_ERR_INVALID_PARAMETER_VALUE, + .relevant_content = statement.parameters[0].name, + }; + } + + component_type = ECSACT_COMPONENT_TYPE_TRANSIENT; + } + } + auto name = std::string(data.component_name.data, data.component_name.length); auto existing_decl = find_by_name(package_id, name); @@ -740,12 +776,14 @@ static ecsact_eval_error eval_component_statement( }; } - ecsact_create_component( + auto comp_id = ecsact_create_component( package_id, data.component_name.data, data.component_name.length ); + ecsact_set_component_type(comp_id, component_type); + return {}; } diff --git a/parse-resolver-runtime/parse-resolver-runtime.cc b/parse-resolver-runtime/parse-resolver-runtime.cc index 5b287dd..b6f49b9 100644 --- a/parse-resolver-runtime/parse-resolver-runtime.cc +++ b/parse-resolver-runtime/parse-resolver-runtime.cc @@ -34,7 +34,8 @@ class composite { struct component_like : composite {}; struct comp_def : component_like { - std::string name; + std::string name; + ecsact_component_type comp_type; }; struct trans_def : component_like { @@ -283,6 +284,7 @@ ecsact_component_id ecsact_create_component( set_package_owner(comp_id, owner); auto& def = comp_defs[comp_id]; def.name = std::string_view(component_name, component_name_len); + def.comp_type = ECSACT_COMPONENT_TYPE_NONE; full_names[decl_id] = pkg_def.name + "." + def.name; return comp_id; @@ -1132,3 +1134,35 @@ auto ecsact_set_system_notify_component_setting( def.notify_settings[component_like_id] = setting; } } + +auto ecsact_meta_component_type( // + ecsact_component_like_id comp_like_id +) -> ecsact_component_type { + auto comp_def = + comp_defs.find(static_cast(comp_like_id)); + if(comp_def == comp_defs.end()) { + // NOTE: this is temporary until we remove the transient fns and instead + // embrace components with transient statement params + auto trans_def = + trans_defs.find(static_cast(comp_like_id)); + if(trans_def != trans_defs.end()) { + return ECSACT_COMPONENT_TYPE_TRANSIENT; + } + + return ECSACT_COMPONENT_TYPE_NONE; + } + + return comp_def->second.comp_type; +} + +auto ecsact_set_component_type( // + ecsact_component_id component_id, + ecsact_component_type comp_type +) -> void { + auto comp_def = comp_defs.find(component_id); + if(comp_def == comp_defs.end()) { + return; + } + + comp_def->second.comp_type = comp_type; +} diff --git a/test/BUILD.bazel b/test/BUILD.bazel index e0575fc..2d7b60f 100644 --- a/test/BUILD.bazel +++ b/test/BUILD.bazel @@ -90,3 +90,19 @@ cc_test( "@googletest//:gtest_main", ], ) + +cc_test( + name = "stream_component", + srcs = ["stream_component.cc"], + copts = copts, + data = [ + "stream_component.ecsact", + ], + deps = [ + ":test_lib", + "@ecsact_interpret", + "@bazel_sundry//bazel_sundry:runfiles", + "@googletest//:gtest", + "@googletest//:gtest_main", + ], +) diff --git a/test/MODULE.bazel b/test/MODULE.bazel index 828f758..5a356d5 100644 --- a/test/MODULE.bazel +++ b/test/MODULE.bazel @@ -3,8 +3,8 @@ 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.5.1") -bazel_dep(name = "ecsact_runtime", version = "0.6.6") +bazel_dep(name = "ecsact_parse", version = "0.5.2") +bazel_dep(name = "ecsact_runtime", version = "0.7.0") bazel_dep(name = "toolchains_llvm", version = "1.0.0", dev_dependency = True) bazel_dep(name = "hedron_compile_commands", dev_dependency = True) @@ -36,3 +36,8 @@ local_path_override( module_name = "ecsact_interpret", path = "..", ) + +local_path_override( + module_name = "ecsact_runtime", + path = "../../ecsact_runtime", +) diff --git a/test/errors/BUILD.bazel b/test/errors/BUILD.bazel index e4969dc..1a931ec 100644 --- a/test/errors/BUILD.bazel +++ b/test/errors/BUILD.bazel @@ -6,6 +6,7 @@ _TESTS = [ "duplicate_notice_components", "invalid_assoc_field", "invalid_notify_settings", + "invalid_stream_component_param_value", "no_capabilities", "no_package_statement_first", "unknown_association_field", diff --git a/test/errors/invalid_stream_component_param_value.cc b/test/errors/invalid_stream_component_param_value.cc new file mode 100644 index 0000000..167c5a6 --- /dev/null +++ b/test/errors/invalid_stream_component_param_value.cc @@ -0,0 +1,12 @@ +#include "gtest/gtest.h" +#include "ecsact/interpret/eval.h" + +#include "test_lib.hh" + +TEST(UnknownParamValue, UnknownStreamComponentParamValue) { + auto errs = ecsact_interpret_test_files({ + "errors/invalid_stream_component_param_value.ecsact", + }); + ASSERT_EQ(errs.size(), 1); + ASSERT_EQ(errs[0].eval_error, ECSACT_EVAL_ERR_INVALID_PARAMETER_VALUE); +} diff --git a/test/errors/invalid_stream_component_param_value.ecsact b/test/errors/invalid_stream_component_param_value.ecsact new file mode 100644 index 0000000..ee48709 --- /dev/null +++ b/test/errors/invalid_stream_component_param_value.ecsact @@ -0,0 +1,5 @@ +package unknown_comp_param_value; + +component UnknownParamValue(stream: huh) { + f32 a; +} diff --git a/test/stream_component.cc b/test/stream_component.cc new file mode 100644 index 0000000..3c4c65b --- /dev/null +++ b/test/stream_component.cc @@ -0,0 +1,56 @@ + +#include "gtest/gtest.h" + +#include "ecsact/runtime/meta.hh" +#include "ecsact/runtime/dynamic.h" +#include "test_lib.hh" + +class StreamComponent : public testing::Test { +public: + ecsact_package_id pkg_id; + +protected: + void SetUp() override { + auto errs = ecsact_interpret_test_files({"stream_component.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(StreamComponent, SanityCheck) { + auto comp_id = get_component_by_name(pkg_id, "MyNormieComponent"); + ASSERT_TRUE(comp_id); + + auto comp_like_id = ecsact_meta_component_type( + ecsact_id_cast(*comp_id) + ); + + ASSERT_EQ(comp_like_id, ECSACT_COMPONENT_TYPE_NONE); +} + +TEST_F(StreamComponent, HasStreamType) { + auto comp_id = get_component_by_name(pkg_id, "MyStreamComponent"); + ASSERT_TRUE(comp_id); + + auto comp_type = ecsact_meta_component_type( + ecsact_id_cast(*comp_id) + ); + + ASSERT_EQ(comp_type, ECSACT_COMPONENT_TYPE_STREAM); +} + +TEST_F(StreamComponent, HasLazyStreamType) { + auto comp_id = get_component_by_name(pkg_id, "MyLazyStreamComponent"); + ASSERT_TRUE(comp_id); + + auto comp_type = ecsact_meta_component_type( + ecsact_id_cast(*comp_id) + ); + + ASSERT_EQ(comp_type, ECSACT_COMPONENT_TYPE_LAZY_STREAM); +} diff --git a/test/stream_component.ecsact b/test/stream_component.ecsact new file mode 100644 index 0000000..8aadd8a --- /dev/null +++ b/test/stream_component.ecsact @@ -0,0 +1,13 @@ +main package eval.stream_component; + +component MyStreamComponent(stream) { + f32 a; +} + +component MyLazyStreamComponent(stream: lazy) { + f32 a; +} + +component MyNormieComponent(stream: false) { + f32 a; +}