Skip to content

feat: system notify settings #124

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
bazel-*/
bazel-*
user.bazelrc
compile_commands.json
external/
.cache/
external
.cache
2 changes: 1 addition & 1 deletion bazel/copts.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ copts = selects.with_or({
"-fexperimental-library",
],
("@rules_cc//cc/compiler:msvc-cl", "@rules_cc//cc/compiler:clang-cl"): [
"/std:c++latest",
"/std:c++20",
"/permissive-",
"/Zc:preprocessor",
],
Expand Down
75 changes: 75 additions & 0 deletions ecsact/detail/grammar.hh
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,61 @@ struct with_statement {
});
};

struct system_notify_statement {
static constexpr auto name() {
return "system notify statement";
}

struct notify_keyword : lexy::transparent_production {
static constexpr auto rule = LEXY_LIT("notify");
static constexpr auto value = lexy::noop;
};

static constexpr auto rule = lexy::dsl::p<notify_keyword> >>
lexy::dsl::opt(lexy::dsl::p<type_name>);

static constexpr auto value = lexy::callback<ecsact_statement>(
[](std::optional<std::string_view> setting_name) {
return ecsact_statement{
.type = ECSACT_STATEMENT_SYSTEM_NOTIFY,
.data{.system_notify_statement{
.setting_name{
.data = setting_name ? setting_name->data() : nullptr,
.length = setting_name ? static_cast<int>(setting_name->size()) : 0,
},
}},
};
}
);
};

struct system_notify_component_statement {
static constexpr auto name() {
return "system notify component statement";
}

static constexpr auto rule = lexy::dsl::p<type_name> >>
lexy::dsl::p<type_name>;

static constexpr auto value = lexy::callback<ecsact_statement>(
[](std::string_view setting_name, std::string_view component_name) {
return ecsact_statement{
.type = ECSACT_STATEMENT_SYSTEM_NOTIFY_COMPONENT,
.data{.system_notify_component_statement{
.setting_name{
.data = setting_name.data(),
.length = static_cast<int>(setting_name.size()),
},
.component_name{
.data = component_name.data(),
.length = static_cast<int>(component_name.size()),
},
}},
};
}
);
};

struct none_statement {
static constexpr auto rule = LEXY_LIT("");
static constexpr auto value = lexy::constant(ecsact_statement{
Expand Down Expand Up @@ -903,6 +958,7 @@ constexpr char system_level_statement_expected_message[] =
using system_level_statement = statement<
system_level_statement_name,
system_level_statement_expected_message,
system_notify_statement,
system_component_statement,
generates_statement,
system_statement>;
Expand All @@ -913,6 +969,7 @@ constexpr char action_level_statement_expected_message[] =
using action_level_statement = statement<
action_level_statement_name,
action_level_statement_expected_message,
system_notify_statement,
field_statement,
system_component_statement,
generates_statement,
Expand Down Expand Up @@ -1008,4 +1065,22 @@ using entity_constraint_level_statement = statement<
entity_constraint_level_statement_expected_message,
none_statement>;

constexpr char system_notify_level_statement_name[] =
"system notify level statement";
constexpr char system_notify_level_statement_expected_message[] =
"expected system notify level statement";
using system_notify_level_statement = statement<
system_notify_level_statement_name,
system_notify_level_statement_expected_message,
system_notify_component_statement>;

constexpr char system_notify_component_level_statement_name[] =
"system notify component level statement";
constexpr char system_notify_component_level_statement_expected_message[] =
"expected system notify component level statement";
using system_notify_component_level_statement = statement<
system_notify_component_level_statement_name,
system_notify_component_level_statement_expected_message,
none_statement>;

} // namespace ecsact::parse::detail::grammar
5 changes: 4 additions & 1 deletion ecsact/ecsact_parse_statement.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ static auto context_grammar(ecsact_statement_type context_type, Fn&& fn) {
return fn(grammar::user_type_field_level_statement{});
case ECSACT_STATEMENT_ENTITY_CONSTRAINT:
return fn(grammar::entity_constraint_level_statement{});
break;
case ECSACT_STATEMENT_SYSTEM_NOTIFY:
return fn(grammar::system_notify_level_statement{});
case ECSACT_STATEMENT_SYSTEM_NOTIFY_COMPONENT:
return fn(grammar::system_notify_component_level_statement{});
}

assert(false && "unhandled context grammar");
Expand Down
42 changes: 29 additions & 13 deletions ecsact/parse/statements.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ typedef enum {
ECSACT_STATEMENT_SYSTEM_GENERATES,
ECSACT_STATEMENT_SYSTEM_WITH_ENTITY,
ECSACT_STATEMENT_ENTITY_CONSTRAINT,
ECSACT_STATEMENT_SYSTEM_NOTIFY,
ECSACT_STATEMENT_SYSTEM_NOTIFY_COMPONENT,
} ecsact_statement_type;

typedef struct {
Expand Down Expand Up @@ -117,20 +119,34 @@ typedef struct {
ecsact_statement_parameter_value value;
} ecsact_statement_parameter;

typedef struct {
/**
* Notify setting name. May be empty.
*/
ecsact_statement_sv setting_name;
} ecsact_system_notify_statement;

typedef struct {
ecsact_statement_sv setting_name;
ecsact_statement_sv component_name;
} ecsact_system_notify_component_statement;

typedef union {
ecsact_package_statement package_statement;
ecsact_import_statement import_statement;
ecsact_component_statement component_statement;
ecsact_transient_statement transient_statement;
ecsact_system_statement system_statement;
ecsact_action_statement action_statement;
ecsact_enum_statement enum_statement;
ecsact_enum_value_statement enum_value_statement;
ecsact_field_statement field_statement;
ecsact_user_type_field_statement user_type_field_statement;
ecsact_system_component_statement system_component_statement;
ecsact_system_with_entity_statement system_with_entity_statement;
ecsact_entity_constraint_statement entity_constraint_statement;
ecsact_package_statement package_statement;
ecsact_import_statement import_statement;
ecsact_component_statement component_statement;
ecsact_transient_statement transient_statement;
ecsact_system_statement system_statement;
ecsact_action_statement action_statement;
ecsact_enum_statement enum_statement;
ecsact_enum_value_statement enum_value_statement;
ecsact_field_statement field_statement;
ecsact_user_type_field_statement user_type_field_statement;
ecsact_system_component_statement system_component_statement;
ecsact_system_with_entity_statement system_with_entity_statement;
ecsact_entity_constraint_statement entity_constraint_statement;
ecsact_system_notify_statement system_notify_statement;
ecsact_system_notify_component_statement system_notify_component_statement;
} ecsact_statement_data;

typedef struct ecsact_statement {
Expand Down
11 changes: 11 additions & 0 deletions test/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,27 @@ _TESTS = [
"sequential_statements",
"system_component_statement",
"system_generates_statement",
"system_notify_statement",
"system_statement",
"system_with_entity_statement",
"unknown_statement",
]

cc_library(
name = "parse_test_util",
hdrs = ["parse_test_util.hh"],
copts = copts,
deps = [
"@googletest//:gtest",
],
)

[cc_test(
name = test,
srcs = ["parse_test_{}.cc".format(test)],
copts = copts,
deps = [
":parse_test_util",
"@ecsact_parse",
"@googletest//:gtest",
"@googletest//:gtest_main",
Expand Down
50 changes: 50 additions & 0 deletions test/parse_test_system_notify_statement.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include "gtest/gtest.h"

#include <string_view>
#include <string>
#include "ecsact/parse.h"

#include "parse_test_util.hh"

using namespace std::string_literals;

TEST(Parse, SystemNotifyShorthand) {
PREPARE_TEST_STATEMENT();
STATEMENT_OK(SYSTEM, "notify always;");

EXPECT_EQ(statement.type, ECSACT_STATEMENT_SYSTEM_NOTIFY);

EXPECT_STATEMENT_SV_EQ(
"always",
statement.data.system_notify_statement.setting_name
);
}

TEST(Parse, SystemNotifyLongForm) {
PREPARE_TEST_STATEMENT();
STATEMENT_OK(SYSTEM_NOTIFY, "always ExampleComponent;");

EXPECT_EQ(statement.type, ECSACT_STATEMENT_SYSTEM_NOTIFY_COMPONENT);

EXPECT_STATEMENT_SV_EQ(
"always",
statement.data.system_notify_component_statement.setting_name
);
EXPECT_STATEMENT_SV_EQ(
"ExampleComponent",
statement.data.system_notify_component_statement.component_name
);

STATEMENT_OK(SYSTEM_NOTIFY, "onchange AnotherComponent;");

EXPECT_EQ(statement.type, ECSACT_STATEMENT_SYSTEM_NOTIFY_COMPONENT);

EXPECT_STATEMENT_SV_EQ(
"onchange",
statement.data.system_notify_component_statement.setting_name
);
EXPECT_STATEMENT_SV_EQ(
"AnotherComponent",
statement.data.system_notify_component_statement.component_name
);
}
59 changes: 59 additions & 0 deletions test/parse_test_util.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#pragma once

#include <string>
#include "gtest/gtest.h"

#define PREPARE_TEST_STATEMENT() \
auto statement = ecsact_statement{}; \
auto context = ecsact_statement{}; \
auto statement_str = std::string{}; \
auto status = ecsact_parse_status{}; \
auto read_amount = int32_t{}; \
static_assert(true, "macro requires semi-colon")

#define STATEMENT_OK(Context, StatementString) \
statement = ecsact_statement{}; \
context = ecsact_statement{}; \
context.type = ECSACT_STATEMENT_##Context; \
context.data = {}; \
\
statement_str = std::string{StatementString}; \
status = ecsact_parse_status{}; \
\
read_amount = ecsact_parse_statement( \
statement_str.data(), \
statement_str.size(), \
&context, \
&statement, \
&status \
); \
\
EXPECT_EQ(status.code, ECSACT_PARSE_STATUS_OK); \
EXPECT_EQ(read_amount, statement_str.size())

#define STATEMENT_BAD(Context, StatementString, BadStatus) \
{ \
auto context = ecsact_statement{}; \
auto statement = ecsact_statement{}; \
context.type = ECSACT_STATEMENT_##Context; \
context.data = {}; \
\
auto statement_str = std::string{StatementString}; \
auto status = ecsact_parse_status{}; \
\
auto read_amount = ecsact_parse_statement( \
statement_str.data(), \
statement_str.size(), \
&context, \
&statement, \
&status \
); \
\
EXPECT_NE(status.code, ECSACT_PARSE_STATUS_OK); \
EXPECT_EQ(status.code, ECSACT_PARSE_STATUS_##BadStatus); \
EXPECT_EQ(read_amount, 0); \
} \
static_assert(true, "Macro requires ;")

#define EXPECT_STATEMENT_SV_EQ(Str, StatementSv) \
EXPECT_EQ(Str, std::string_view(StatementSv.data, StatementSv.length))