Skip to content

Commit 0a58abf

Browse files
authored
feat: system notify settings (#124)
1 parent 427d53f commit 0a58abf

File tree

8 files changed

+232
-18
lines changed

8 files changed

+232
-18
lines changed

.gitignore

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
bazel-*/
1+
bazel-*
22
user.bazelrc
33
compile_commands.json
4-
external/
5-
.cache/
4+
external
5+
.cache

bazel/copts.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ copts = selects.with_or({
1010
"-fexperimental-library",
1111
],
1212
("@rules_cc//cc/compiler:msvc-cl", "@rules_cc//cc/compiler:clang-cl"): [
13-
"/std:c++latest",
13+
"/std:c++20",
1414
"/permissive-",
1515
"/Zc:preprocessor",
1616
],

ecsact/detail/grammar.hh

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,61 @@ struct with_statement {
775775
});
776776
};
777777

778+
struct system_notify_statement {
779+
static constexpr auto name() {
780+
return "system notify statement";
781+
}
782+
783+
struct notify_keyword : lexy::transparent_production {
784+
static constexpr auto rule = LEXY_LIT("notify");
785+
static constexpr auto value = lexy::noop;
786+
};
787+
788+
static constexpr auto rule = lexy::dsl::p<notify_keyword> >>
789+
lexy::dsl::opt(lexy::dsl::p<type_name>);
790+
791+
static constexpr auto value = lexy::callback<ecsact_statement>(
792+
[](std::optional<std::string_view> setting_name) {
793+
return ecsact_statement{
794+
.type = ECSACT_STATEMENT_SYSTEM_NOTIFY,
795+
.data{.system_notify_statement{
796+
.setting_name{
797+
.data = setting_name ? setting_name->data() : nullptr,
798+
.length = setting_name ? static_cast<int>(setting_name->size()) : 0,
799+
},
800+
}},
801+
};
802+
}
803+
);
804+
};
805+
806+
struct system_notify_component_statement {
807+
static constexpr auto name() {
808+
return "system notify component statement";
809+
}
810+
811+
static constexpr auto rule = lexy::dsl::p<type_name> >>
812+
lexy::dsl::p<type_name>;
813+
814+
static constexpr auto value = lexy::callback<ecsact_statement>(
815+
[](std::string_view setting_name, std::string_view component_name) {
816+
return ecsact_statement{
817+
.type = ECSACT_STATEMENT_SYSTEM_NOTIFY_COMPONENT,
818+
.data{.system_notify_component_statement{
819+
.setting_name{
820+
.data = setting_name.data(),
821+
.length = static_cast<int>(setting_name.size()),
822+
},
823+
.component_name{
824+
.data = component_name.data(),
825+
.length = static_cast<int>(component_name.size()),
826+
},
827+
}},
828+
};
829+
}
830+
);
831+
};
832+
778833
struct none_statement {
779834
static constexpr auto rule = LEXY_LIT("");
780835
static constexpr auto value = lexy::constant(ecsact_statement{
@@ -903,6 +958,7 @@ constexpr char system_level_statement_expected_message[] =
903958
using system_level_statement = statement<
904959
system_level_statement_name,
905960
system_level_statement_expected_message,
961+
system_notify_statement,
906962
system_component_statement,
907963
generates_statement,
908964
system_statement>;
@@ -913,6 +969,7 @@ constexpr char action_level_statement_expected_message[] =
913969
using action_level_statement = statement<
914970
action_level_statement_name,
915971
action_level_statement_expected_message,
972+
system_notify_statement,
916973
field_statement,
917974
system_component_statement,
918975
generates_statement,
@@ -1008,4 +1065,22 @@ using entity_constraint_level_statement = statement<
10081065
entity_constraint_level_statement_expected_message,
10091066
none_statement>;
10101067

1068+
constexpr char system_notify_level_statement_name[] =
1069+
"system notify level statement";
1070+
constexpr char system_notify_level_statement_expected_message[] =
1071+
"expected system notify level statement";
1072+
using system_notify_level_statement = statement<
1073+
system_notify_level_statement_name,
1074+
system_notify_level_statement_expected_message,
1075+
system_notify_component_statement>;
1076+
1077+
constexpr char system_notify_component_level_statement_name[] =
1078+
"system notify component level statement";
1079+
constexpr char system_notify_component_level_statement_expected_message[] =
1080+
"expected system notify component level statement";
1081+
using system_notify_component_level_statement = statement<
1082+
system_notify_component_level_statement_name,
1083+
system_notify_component_level_statement_expected_message,
1084+
none_statement>;
1085+
10111086
} // namespace ecsact::parse::detail::grammar

ecsact/ecsact_parse_statement.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ static auto context_grammar(ecsact_statement_type context_type, Fn&& fn) {
4545
return fn(grammar::user_type_field_level_statement{});
4646
case ECSACT_STATEMENT_ENTITY_CONSTRAINT:
4747
return fn(grammar::entity_constraint_level_statement{});
48-
break;
48+
case ECSACT_STATEMENT_SYSTEM_NOTIFY:
49+
return fn(grammar::system_notify_level_statement{});
50+
case ECSACT_STATEMENT_SYSTEM_NOTIFY_COMPONENT:
51+
return fn(grammar::system_notify_component_level_statement{});
4952
}
5053

5154
assert(false && "unhandled context grammar");

ecsact/parse/statements.h

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ typedef enum {
2424
ECSACT_STATEMENT_SYSTEM_GENERATES,
2525
ECSACT_STATEMENT_SYSTEM_WITH_ENTITY,
2626
ECSACT_STATEMENT_ENTITY_CONSTRAINT,
27+
ECSACT_STATEMENT_SYSTEM_NOTIFY,
28+
ECSACT_STATEMENT_SYSTEM_NOTIFY_COMPONENT,
2729
} ecsact_statement_type;
2830

2931
typedef struct {
@@ -117,20 +119,34 @@ typedef struct {
117119
ecsact_statement_parameter_value value;
118120
} ecsact_statement_parameter;
119121

122+
typedef struct {
123+
/**
124+
* Notify setting name. May be empty.
125+
*/
126+
ecsact_statement_sv setting_name;
127+
} ecsact_system_notify_statement;
128+
129+
typedef struct {
130+
ecsact_statement_sv setting_name;
131+
ecsact_statement_sv component_name;
132+
} ecsact_system_notify_component_statement;
133+
120134
typedef union {
121-
ecsact_package_statement package_statement;
122-
ecsact_import_statement import_statement;
123-
ecsact_component_statement component_statement;
124-
ecsact_transient_statement transient_statement;
125-
ecsact_system_statement system_statement;
126-
ecsact_action_statement action_statement;
127-
ecsact_enum_statement enum_statement;
128-
ecsact_enum_value_statement enum_value_statement;
129-
ecsact_field_statement field_statement;
130-
ecsact_user_type_field_statement user_type_field_statement;
131-
ecsact_system_component_statement system_component_statement;
132-
ecsact_system_with_entity_statement system_with_entity_statement;
133-
ecsact_entity_constraint_statement entity_constraint_statement;
135+
ecsact_package_statement package_statement;
136+
ecsact_import_statement import_statement;
137+
ecsact_component_statement component_statement;
138+
ecsact_transient_statement transient_statement;
139+
ecsact_system_statement system_statement;
140+
ecsact_action_statement action_statement;
141+
ecsact_enum_statement enum_statement;
142+
ecsact_enum_value_statement enum_value_statement;
143+
ecsact_field_statement field_statement;
144+
ecsact_user_type_field_statement user_type_field_statement;
145+
ecsact_system_component_statement system_component_statement;
146+
ecsact_system_with_entity_statement system_with_entity_statement;
147+
ecsact_entity_constraint_statement entity_constraint_statement;
148+
ecsact_system_notify_statement system_notify_statement;
149+
ecsact_system_notify_component_statement system_notify_component_statement;
134150
} ecsact_statement_data;
135151

136152
typedef struct ecsact_statement {

test/BUILD.bazel

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,27 @@ _TESTS = [
1414
"sequential_statements",
1515
"system_component_statement",
1616
"system_generates_statement",
17+
"system_notify_statement",
1718
"system_statement",
1819
"system_with_entity_statement",
1920
"unknown_statement",
2021
]
2122

23+
cc_library(
24+
name = "parse_test_util",
25+
hdrs = ["parse_test_util.hh"],
26+
copts = copts,
27+
deps = [
28+
"@googletest//:gtest",
29+
],
30+
)
31+
2232
[cc_test(
2333
name = test,
2434
srcs = ["parse_test_{}.cc".format(test)],
2535
copts = copts,
2636
deps = [
37+
":parse_test_util",
2738
"@ecsact_parse",
2839
"@googletest//:gtest",
2940
"@googletest//:gtest_main",
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#include "gtest/gtest.h"
2+
3+
#include <string_view>
4+
#include <string>
5+
#include "ecsact/parse.h"
6+
7+
#include "parse_test_util.hh"
8+
9+
using namespace std::string_literals;
10+
11+
TEST(Parse, SystemNotifyShorthand) {
12+
PREPARE_TEST_STATEMENT();
13+
STATEMENT_OK(SYSTEM, "notify always;");
14+
15+
EXPECT_EQ(statement.type, ECSACT_STATEMENT_SYSTEM_NOTIFY);
16+
17+
EXPECT_STATEMENT_SV_EQ(
18+
"always",
19+
statement.data.system_notify_statement.setting_name
20+
);
21+
}
22+
23+
TEST(Parse, SystemNotifyLongForm) {
24+
PREPARE_TEST_STATEMENT();
25+
STATEMENT_OK(SYSTEM_NOTIFY, "always ExampleComponent;");
26+
27+
EXPECT_EQ(statement.type, ECSACT_STATEMENT_SYSTEM_NOTIFY_COMPONENT);
28+
29+
EXPECT_STATEMENT_SV_EQ(
30+
"always",
31+
statement.data.system_notify_component_statement.setting_name
32+
);
33+
EXPECT_STATEMENT_SV_EQ(
34+
"ExampleComponent",
35+
statement.data.system_notify_component_statement.component_name
36+
);
37+
38+
STATEMENT_OK(SYSTEM_NOTIFY, "onchange AnotherComponent;");
39+
40+
EXPECT_EQ(statement.type, ECSACT_STATEMENT_SYSTEM_NOTIFY_COMPONENT);
41+
42+
EXPECT_STATEMENT_SV_EQ(
43+
"onchange",
44+
statement.data.system_notify_component_statement.setting_name
45+
);
46+
EXPECT_STATEMENT_SV_EQ(
47+
"AnotherComponent",
48+
statement.data.system_notify_component_statement.component_name
49+
);
50+
}

test/parse_test_util.hh

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include "gtest/gtest.h"
5+
6+
#define PREPARE_TEST_STATEMENT() \
7+
auto statement = ecsact_statement{}; \
8+
auto context = ecsact_statement{}; \
9+
auto statement_str = std::string{}; \
10+
auto status = ecsact_parse_status{}; \
11+
auto read_amount = int32_t{}; \
12+
static_assert(true, "macro requires semi-colon")
13+
14+
#define STATEMENT_OK(Context, StatementString) \
15+
statement = ecsact_statement{}; \
16+
context = ecsact_statement{}; \
17+
context.type = ECSACT_STATEMENT_##Context; \
18+
context.data = {}; \
19+
\
20+
statement_str = std::string{StatementString}; \
21+
status = ecsact_parse_status{}; \
22+
\
23+
read_amount = ecsact_parse_statement( \
24+
statement_str.data(), \
25+
statement_str.size(), \
26+
&context, \
27+
&statement, \
28+
&status \
29+
); \
30+
\
31+
EXPECT_EQ(status.code, ECSACT_PARSE_STATUS_OK); \
32+
EXPECT_EQ(read_amount, statement_str.size())
33+
34+
#define STATEMENT_BAD(Context, StatementString, BadStatus) \
35+
{ \
36+
auto context = ecsact_statement{}; \
37+
auto statement = ecsact_statement{}; \
38+
context.type = ECSACT_STATEMENT_##Context; \
39+
context.data = {}; \
40+
\
41+
auto statement_str = std::string{StatementString}; \
42+
auto status = ecsact_parse_status{}; \
43+
\
44+
auto read_amount = ecsact_parse_statement( \
45+
statement_str.data(), \
46+
statement_str.size(), \
47+
&context, \
48+
&statement, \
49+
&status \
50+
); \
51+
\
52+
EXPECT_NE(status.code, ECSACT_PARSE_STATUS_OK); \
53+
EXPECT_EQ(status.code, ECSACT_PARSE_STATUS_##BadStatus); \
54+
EXPECT_EQ(read_amount, 0); \
55+
} \
56+
static_assert(true, "Macro requires ;")
57+
58+
#define EXPECT_STATEMENT_SV_EQ(Str, StatementSv) \
59+
EXPECT_EQ(Str, std::string_view(StatementSv.data, StatementSv.length))

0 commit comments

Comments
 (0)